Skip to content

Commit

Permalink
Merge pull request #245 from mengqiy/sscp
Browse files Browse the repository at this point in the history
implement SelfSignedCertProvisioner
  • Loading branch information
droot committed Jun 6, 2018
2 parents fea9e3a + 6c9013c commit a08cda9
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@ limitations under the License.

package certprovisioner

// Certs hosts a private key, its corresponding serving certificate and
// the CA certificate that signs the serving certificate.
type Certs struct {
Key []byte
Cert []byte
CACert []byte
}

// CertProvisioner is an interface to provision the serving certificate.
type CertProvisioner interface {
// ProvisionServingCert returns the key, serving certificate and the CA certificate.
ProvisionServingCert() (key []byte, cert []byte, caCert []byte, err error)
// ProvisionServingCert returns a Certs struct.
ProvisionServingCert() (*Certs, error)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,9 @@ limitations under the License.

package certprovisioner

func ExampleSelfSignedCertProvisioner() {
cp := SelfSignedCertProvisioner{
Organization: "k8s.io",
DNSNames: []string{"myDNSName"},
ValidDays: 365,
}
import "fmt"

key, cert, caCert, err := cp.ProvisionServingCert()
if err != nil {
// handle error
}
func ExampleServiceToCommonName() {
fmt.Println(ServiceToCommonName("myservicenamespace", "myservicename"))
// Output: myservicename.myservicenamespace.svc
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ Package certprovisioner provides an interface and implementation to provision ce
Create a implementation instance of certprovisioner.
cp := SelfSignedCertProvisioner{
// your configuration
CommonName: "foo.bar.com"
}
Provision the certificates.
key, cert, caCert, err := cp.ProvisionServingCert()
certs, err := cp.ProvisionServingCert()
if err != nil {
// handle error
}
Expand Down
73 changes: 73 additions & 0 deletions pkg/webhook/certprovisioner/selfsignedcertprovisioner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package certprovisioner

import (
"crypto/x509"
"fmt"

"k8s.io/client-go/util/cert"
)

// ServiceToCommonName generates the CommonName for the certificate when using a k8s service.
func ServiceToCommonName(serviceNamespace, serviceName string) string {
return fmt.Sprintf("%s.%s.svc", serviceName, serviceNamespace)
}

// SelfSignedCertProvisioner implements the CertProvisioner interface.
// It provisions self-signed certificates.
type SelfSignedCertProvisioner struct {
// Required Common Name
CommonName string
}

var _ CertProvisioner = &SelfSignedCertProvisioner{}

// ProvisionServingCert creates and returns a CA certificate, certificate and
// key for the server. serverKey and serverCert are used by the server
// to establish trust for clients, CA certificate is used by the
// client to verify the server authentication chain.
// The cert will be valid for 365 days.
func (cp *SelfSignedCertProvisioner) ProvisionServingCert() (*Certs, error) {
signingKey, err := cert.NewPrivateKey()
if err != nil {
return nil, fmt.Errorf("failed to create the CA private key: %v", err)
}
signingCert, err := cert.NewSelfSignedCACert(cert.Config{CommonName: "webhook-cert-ca"}, signingKey)
if err != nil {
return nil, fmt.Errorf("failed to create the CA cert: %v", err)
}
key, err := cert.NewPrivateKey()
if err != nil {
return nil, fmt.Errorf("failed to create the private key: %v", err)
}
signedCert, err := cert.NewSignedCert(
cert.Config{
CommonName: cp.CommonName,
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
},
key, signingCert, signingKey,
)
if err != nil {
return nil, fmt.Errorf("failed to create the cert: %v", err)
}
return &Certs{
Key: cert.EncodePrivateKeyPEM(key),
Cert: cert.EncodeCertPEM(signedCert),
CACert: cert.EncodeCertPEM(signingCert),
}, nil
}
56 changes: 56 additions & 0 deletions pkg/webhook/certprovisioner/selfsignedcertprovisioner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package certprovisioner

import (
"crypto/x509"
"encoding/pem"
"testing"
)

func TestProvisionServingCert(t *testing.T) {
cn := "mysvc.myns.svc"
cp := SelfSignedCertProvisioner{CommonName: cn}
certs, err := cp.ProvisionServingCert()

// First, create the set of root certificates. For this example we only
// have one. It's also possible to omit this in order to use the
// default root set of the current operating system.
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM(certs.CACert)
if !ok {
t.Fatalf("failed to parse root certificate: %s", certs.CACert)
}

block, _ := pem.Decode(certs.Cert)
if block == nil {
t.Fatalf("failed to parse certificate PEM: %s", certs.Cert)
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatalf("failed to parse certificate: %v", err)
}

opts := x509.VerifyOptions{
DNSName: cn,
Roots: roots,
}

if _, err := cert.Verify(opts); err != nil {
t.Fatalf("failed to verify certificate: %v", err)
}
}
36 changes: 0 additions & 36 deletions pkg/webhook/internal/certprovisioner/selfsignedcertprovisioner.go

This file was deleted.

0 comments on commit a08cda9

Please sign in to comment.