Skip to content

Commit

Permalink
add support for ecdsa keys
Browse files Browse the repository at this point in the history
Signed-off-by: Vinny Sabatini <[email protected]>
  • Loading branch information
vinny-sabatini committed Jun 1, 2023
1 parent 9be1ba4 commit 362411d
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 9 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ metadata:
cert-manager.io/alt-names: "mycooldomain.com,mysecondarydomain.com" # Optional, no default
cert-manager.io/ip-sans: "10.20.30.40,192.168.192.168" # Optional, no default
cert-manager.io/uri-sans: "spiffe://trustdomain/workload" # Optional, no default
cert-manager.io/private-key-algorithm: "ECDSA" # Optional, defaults to RSA
spec:
host: app.service.clustername.domain.com # will be added to the Subject Alternative Names of the CertificateRequest
port:
Expand Down
52 changes: 43 additions & 9 deletions internal/controller/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,29 @@ func (r *Route) hasNextPrivateKey(route *routev1.Route) bool {
}

func (r *Route) generateNextPrivateKey(ctx context.Context, route *routev1.Route) error {
// TODO: different kinds of key
key, err := utilpki.GenerateRSAPrivateKey(utilpki.MinRSAKeySize)
if err != nil {
return fmt.Errorf("could not generate RSA Key: %w", err)
privateKeyAlgorithm, found := route.Annotations[cmapi.PrivateKeyAlgorithmAnnotationKey]
if !found {
privateKeyAlgorithm = string(cmapi.RSAKeyAlgorithm)
}

encodedKey, err := utilpki.EncodePrivateKey(key, cmapi.PKCS1)
var privateKey crypto.PrivateKey
var err error
switch privateKeyAlgorithm {
case string(cmapi.ECDSAKeyAlgorithm):
privateKey, err = utilpki.GenerateECPrivateKey(utilpki.ECCurve256)
if err != nil {
return fmt.Errorf("could not generate ECDSA key: %w", err)
}
case string(cmapi.RSAKeyAlgorithm):
privateKey, err = utilpki.GenerateRSAPrivateKey(utilpki.MinRSAKeySize)
if err != nil {
return fmt.Errorf("could not generate RSA Key: %w", err)
}
default:
return fmt.Errorf("invalid private key algorithm: %s", privateKeyAlgorithm)
}
encodedKey, err := utilpki.EncodePrivateKey(privateKey, cmapi.PrivateKeyEncoding(cmapi.PKCS1))
if err != nil {
return fmt.Errorf("could not encode RSA Key: %w", err)
return fmt.Errorf("could not encode %s key: %w", privateKeyAlgorithm, err)
}
route.Annotations[cmapi.IsNextPrivateKeySecretLabelKey] = string(encodedKey)
_, err = r.routeClient.RouteV1().Routes(route.Namespace).Update(ctx, route, metav1.UpdateOptions{})
Expand Down Expand Up @@ -326,12 +340,32 @@ func (r *Route) createNextCR(ctx context.Context, route *routev1.Route, revision
}
}

privateKeyAlgorithm, found := route.Annotations[cmapi.PrivateKeyAlgorithmAnnotationKey]
if !found {
privateKeyAlgorithm = string(cmapi.RSAKeyAlgorithm)
}

var signatureAlgorithm x509.SignatureAlgorithm
var publicKeyAlgorithm x509.PublicKeyAlgorithm
switch privateKeyAlgorithm {
case string(cmapi.ECDSAKeyAlgorithm):
signatureAlgorithm = x509.ECDSAWithSHA256
publicKeyAlgorithm = x509.ECDSA

case string(cmapi.RSAKeyAlgorithm):
signatureAlgorithm = x509.SHA256WithRSA
publicKeyAlgorithm = x509.RSA

default:
return fmt.Errorf("invalid private key algorithm, %s", privateKeyAlgorithm)
}

csr, err := x509.CreateCertificateRequest(
rand.Reader,
&x509.CertificateRequest{
Version: 0,
SignatureAlgorithm: x509.SHA256WithRSA,
PublicKeyAlgorithm: x509.RSA,
SignatureAlgorithm: signatureAlgorithm,
PublicKeyAlgorithm: publicKeyAlgorithm,
Subject: pkix.Name{
CommonName: route.Annotations[cmapi.CommonNameAnnotationKey],
},
Expand Down
46 changes: 46 additions & 0 deletions internal/controller/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,44 @@ func TestRoute_generateNextPrivateKey(t *testing.T) {
want: nil,
wantedEvents: []string{"Normal Issuing Generated Private Key for route"},
},
{
name: "rsa annotated route has no private key",
route: &routev1.Route{
ObjectMeta: metav1.ObjectMeta{
Name: "some-route",
Namespace: "some-namespace",
CreationTimestamp: metav1.Time{Time: time.Now().Add(-time.Hour * 24 * 30)},
Annotations: map[string]string{
cmapi.IssuerNameAnnotationKey: "some-issuer",
cmapi.PrivateKeyAlgorithmAnnotationKey: "RSA",
},
},
Spec: routev1.RouteSpec{
Host: "some-host.some-domain.tld",
},
},
want: nil,
wantedEvents: []string{"Normal Issuing Generated Private Key for route"},
},
{
name: "ecdsa annotated route has no private key",
route: &routev1.Route{
ObjectMeta: metav1.ObjectMeta{
Name: "some-route",
Namespace: "some-namespace",
CreationTimestamp: metav1.Time{Time: time.Now().Add(-time.Hour * 24 * 30)},
Annotations: map[string]string{
cmapi.IssuerNameAnnotationKey: "some-issuer",
cmapi.PrivateKeyAlgorithmAnnotationKey: "ECDSA",
},
},
Spec: routev1.RouteSpec{
Host: "some-host.some-domain.tld",
},
},
want: nil,
wantedEvents: []string{"Normal Issuing Generated Private Key for route"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -467,6 +505,14 @@ func TestRoute_generateNextPrivateKey(t *testing.T) {
assert.NoError(t, err)
_, err = utilpki.DecodePrivateKeyBytes([]byte(actualRoute.Annotations[cmapi.IsNextPrivateKeySecretLabelKey]))
assert.NoError(t, err)
switch tt.route.Annotations[cmapi.PrivateKeyAlgorithmAnnotationKey] {
case string(cmapi.RSAKeyAlgorithm), "":
assert.Contains(t, actualRoute.Annotations[cmapi.IsNextPrivateKeySecretLabelKey], "BEGIN RSA PRIVATE KEY")
case string(cmapi.ECDSAKeyAlgorithm):
assert.Contains(t, actualRoute.Annotations[cmapi.IsNextPrivateKeySecretLabelKey], "BEGIN EC PRIVATE KEY")
default:
t.Errorf("Failing %v", tt.route.Annotations[cmapi.PrivateKeyAlgorithmAnnotationKey])
}
})
}
}
Expand Down

0 comments on commit 362411d

Please sign in to comment.