Skip to content

Commit

Permalink
Merge pull request #114 from Nordix/cert
Browse files Browse the repository at this point in the history
Remove usage of k8s api certificates/v1beta1 and use self signed certificate
  • Loading branch information
zshi-redhat authored Oct 11, 2021
2 parents 6d76075 + b61afb3 commit 4f0659b
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 59 deletions.
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,16 @@ github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU=
github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e h1:mvOa4+/DXStR4ZXOks/UsjeFdn5O5JpLUtzqk9U8xXw=
github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8=
github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb h1:vxqkjztXSaPVDc8FQCdHTaejm2x747f6yPbnu1h2xkg=
github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
Expand Down
90 changes: 31 additions & 59 deletions pkg/installer/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@ package installer

import (
"context"
"fmt"
"io/ioutil"
"strings"
"time"

"github.com/cloudflare/cfssl/csr"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/initca"
cfsigner "github.com/cloudflare/cfssl/signer"
"github.com/cloudflare/cfssl/signer/local"
"github.com/golang/glog"
"github.com/pkg/errors"

arv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/api/certificates/v1beta1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
Expand All @@ -40,6 +43,7 @@ var (
)

const keyBitLength = 3072
const CAExpiration = "630720000s"

func generateCSR() ([]byte, []byte, error) {
glog.Infof("generating Certificate Signing Request")
Expand All @@ -55,66 +59,28 @@ func generateCSR() ([]byte, []byte, error) {
return csr.ParseRequest(certRequest)
}

func getSignedCertificate(request []byte) ([]byte, error) {
csrName := strings.Join([]string{prefix, "csr"}, "-")
csr, err := clientset.CertificatesV1beta1().CertificateSigningRequests().Get(context.TODO(), csrName, metav1.GetOptions{})
if csr != nil || err == nil {
glog.Infof("CSR %s already exists, removing it first", csrName)
clientset.CertificatesV1beta1().CertificateSigningRequests().Delete(context.TODO(), csrName, metav1.DeleteOptions{})
}

glog.Infof("creating new CSR %s", csrName)
/* build Kubernetes CSR object */
csr = &v1beta1.CertificateSigningRequest{}
csr.ObjectMeta.Name = csrName
csr.ObjectMeta.Namespace = namespace
csr.Spec.Request = request
csr.Spec.Groups = []string{"system:authenticated"}
csr.Spec.Usages = []v1beta1.KeyUsage{v1beta1.UsageDigitalSignature, v1beta1.UsageServerAuth, v1beta1.UsageKeyEncipherment}

/* push CSR to Kubernetes API server */
csr, err = clientset.CertificatesV1beta1().CertificateSigningRequests().Create(context.TODO(), csr, metav1.CreateOptions{})
func generateCACertificate() (*local.Signer, []byte, error) {
certRequest := csr.New()
certRequest.KeyRequest = &csr.KeyRequest{A: "rsa", S: keyBitLength}
certRequest.CN = "Kubernetes NRI"
certRequest.CA = &csr.CAConfig{Expiry: CAExpiration}
cert, _, key, err := initca.New(certRequest)
if err != nil {
return nil, errors.Wrap(err, "error creating CSR in Kubernetes API: %s")
return nil, nil, fmt.Errorf("creating CA certificate failed: %v", err)
}
glog.Infof("CSR pushed to the Kubernetes API")

if csr.Status.Certificate != nil {
glog.Infof("using already issued certificate for CSR %s", csrName)
return csr.Status.Certificate, nil
parsedKey, err := helpers.ParsePrivateKeyPEM(key)
if err != nil {
return nil, nil, fmt.Errorf("parsing private key pem failed: %v", err)
}
/* approve certificate in K8s API */
csr.ObjectMeta.Name = csrName
csr.ObjectMeta.Namespace = namespace
csr.Status.Conditions = append(csr.Status.Conditions, v1beta1.CertificateSigningRequestCondition{
Type: v1beta1.CertificateApproved,
Reason: "Approved by net-attach-def admission controller installer",
Message: "This CSR was approved by net-attach-def admission controller installer.",
LastUpdateTime: metav1.Now(),
})
_, err = clientset.CertificatesV1beta1().CertificateSigningRequests().UpdateApproval(context.TODO(), csr, metav1.UpdateOptions{})
glog.Infof("certificate approval sent")
parsedCert, err := helpers.ParseCertificatePEM(cert)
if err != nil {
return nil, errors.Wrap(err, "error approving CSR in Kubernetes API")
return nil, nil, fmt.Errorf("parse certificate failed: %v", err)
}

/* wait for the cert to be issued */
glog.Infof("waiting for the signed certificate to be issued...")
start := time.Now()
for range time.Tick(time.Second) {
csr, err = clientset.CertificatesV1beta1().CertificateSigningRequests().Get(context.TODO(), csrName, metav1.GetOptions{})
if err != nil {
return nil, errors.Wrap(err, "error getting signed ceritificate from the API server")
}
if csr.Status.Certificate != nil {
return csr.Status.Certificate, nil
}
if time.Since(start) > 60*time.Second {
break
}
signer, err := local.NewSigner(parsedKey, parsedCert, cfsigner.DefaultSigAlgo(parsedKey), nil)
if err != nil {
return nil, nil, fmt.Errorf("failed to create signer: %v", err)
}

return nil, errors.New("error getting certificate from the API server: request timed out - verify that Kubernetes certificate signer is setup, more at https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/#a-note-to-cluster-administrators")
return signer, cert, nil
}

func writeToFile(certificate, key []byte, certFilename, keyFilename string) error {
Expand Down Expand Up @@ -256,15 +222,21 @@ func Install(k8sNamespace, namePrefix, failurePolicy string) {
namespace = k8sNamespace
prefix = namePrefix

signer, caCertificate, err := generateCACertificate()
if err != nil {
glog.Fatalf("Error generating CA certificate and signer: %s", err)
}

/* generate CSR and private key */
csr, key, err := generateCSR()
if err != nil {
glog.Fatalf("error generating CSR and private key: %s", err)
}
glog.Infof("raw CSR and private key successfully created")

/* obtain signed certificate */
certificate, err := getSignedCertificate(csr)
certificate, err := signer.Sign(cfsigner.SignRequest{
Request: string(csr),
})
if err != nil {
glog.Fatalf("error getting signed certificate: %s", err)
}
Expand All @@ -277,7 +249,7 @@ func Install(k8sNamespace, namePrefix, failurePolicy string) {
glog.Infof("certificate and key written to files")

/* create webhook configurations */
err = createMutatingWebhookConfiguration(certificate, failurePolicy)
err = createMutatingWebhookConfiguration(caCertificate, failurePolicy)
if err != nil {
glog.Fatalf("error creating mutating webhook configuration: %s", err)
}
Expand Down

0 comments on commit 4f0659b

Please sign in to comment.