Skip to content

Commit

Permalink
Rewrite AWS issuer
Browse files Browse the repository at this point in the history
  • Loading branch information
johanbrandhorst committed Aug 22, 2021
1 parent 168d95c commit 14a03e7
Show file tree
Hide file tree
Showing 7 changed files with 295 additions and 1,302 deletions.
9 changes: 7 additions & 2 deletions cmd/proxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,14 @@ func awsIssuer(conf envtypes.AWS) (*aws.Issuer, error) {
}
ac := awssdk.Config{}
ac.Region = conf.Region
ac.Credentials = awssdk.NewStaticCredentialsProvider(conf.AccessKeyID, conf.AccessKeySecret, "")
ac.Credentials = awssdk.CredentialsProviderFunc(func(c context.Context) (awssdk.Credentials, error) {
return awssdk.Credentials{
AccessKeyID: conf.AccessKeyID,
SecretAccessKey: conf.AccessKeySecret,
}, nil
})
return &aws.Issuer{
Client: acmpca.New(ac),
Client: acmpca.NewFromConfig(ac),
CertificateAuthorityARN: conf.CertificateAuthorityARN,
TimeToLive: conf.TimeToLive,
}, nil
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ go 1.12

require (
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/aws/aws-sdk-go-v2 v0.7.0
github.com/aws/aws-sdk-go-v2 v1.8.1
github.com/aws/aws-sdk-go-v2/service/acmpca v1.6.3
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cloudflare/cfssl v1.4.0
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
github.com/frankban/quicktest v1.4.1 // indirect
github.com/go-test/deep v1.0.2 // indirect
github.com/golang/protobuf v1.3.2
github.com/google/go-cmp v0.3.1 // indirect
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
github.com/hashicorp/vault/api v1.0.5-0.20200117231345-460d63e36490
github.com/hashicorp/vault/sdk v0.1.14-0.20200305172021-03a3749f220d // indirect
Expand Down
84 changes: 17 additions & 67 deletions go.sum

Large diffs are not rendered by default.

73 changes: 43 additions & 30 deletions issuers/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import (
"encoding/pem"
"errors"
"fmt"
"sync"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/acmpca"
iface "github.com/aws/aws-sdk-go-v2/service/acmpca/acmpcaiface"
"github.com/aws/aws-sdk-go-v2/service/acmpca/types"

"github.com/johanbrandhorst/certify"
"github.com/johanbrandhorst/certify/internal/csr"
Expand All @@ -30,7 +32,7 @@ type Issuer struct {
// conf.Region = endpoints.EuWest2RegionID
// conf.Credentials = aws.NewStaticCredentialsProvider("YOURKEY", "YOURKEYSECRET", "")
// cli := acmpca.New(conf)
Client iface.ACMPCAAPI
Client *acmpca.Client
// CertificateAuthorityARN specifies the ARN of a pre-created CA
// which will be used to issue the certificates.
CertificateAuthorityARN string
Expand All @@ -40,52 +42,63 @@ type Issuer struct {
// If unset, defaults to 30 days.
TimeToLive int

initOnce sync.Once
initErr error
caCert *x509.Certificate
signAlgo acmpca.SigningAlgorithm
signAlgo types.SigningAlgorithm
waiter *acmpca.CertificateIssuedWaiter
}

// Issue issues a certificate from the configured AWS CA backend.
func (i Issuer) Issue(ctx context.Context, commonName string, conf *certify.CertConfig) (*tls.Certificate, error) {
if i.caCert == nil {
caReq := i.Client.GetCertificateAuthorityCertificateRequest(&acmpca.GetCertificateAuthorityCertificateInput{
i.initOnce.Do(func() {
i.waiter = acmpca.NewCertificateIssuedWaiter(i.Client)

caResp, err := i.Client.GetCertificateAuthorityCertificate(ctx, &acmpca.GetCertificateAuthorityCertificateInput{
CertificateAuthorityArn: aws.String(i.CertificateAuthorityARN),
})

caResp, err := caReq.Send()
if err != nil {
return nil, err
i.initErr = err
return
}

caBlock, _ := pem.Decode([]byte(*caResp.Certificate))
if caBlock == nil {
return nil, errors.New("could not parse AWS CA cert")
i.initErr = errors.New("could not parse AWS CA cert")
return
}

if caBlock.Type != "CERTIFICATE" {
return nil, errors.New("saw unexpected PEM Type while requesting AWS CA cert: " + caBlock.Type)
i.initErr = errors.New("saw unexpected PEM Type while requesting AWS CA cert: " + caBlock.Type)
return
}

i.caCert, err = x509.ParseCertificate(caBlock.Bytes)
if err != nil {
return nil, err
i.initErr = err
return
}

switch i.caCert.SignatureAlgorithm {
case x509.SHA256WithRSA:
i.signAlgo = acmpca.SigningAlgorithmSha256withrsa
i.signAlgo = types.SigningAlgorithmSha256withrsa
case x509.SHA384WithRSA:
i.signAlgo = acmpca.SigningAlgorithmSha384withrsa
i.signAlgo = types.SigningAlgorithmSha384withrsa
case x509.SHA512WithRSA:
i.signAlgo = acmpca.SigningAlgorithmSha512withrsa
i.signAlgo = types.SigningAlgorithmSha512withrsa
case x509.ECDSAWithSHA256:
i.signAlgo = acmpca.SigningAlgorithmSha256withecdsa
i.signAlgo = types.SigningAlgorithmSha256withecdsa
case x509.ECDSAWithSHA384:
i.signAlgo = acmpca.SigningAlgorithmSha384withecdsa
i.signAlgo = types.SigningAlgorithmSha384withecdsa
case x509.ECDSAWithSHA512:
i.signAlgo = acmpca.SigningAlgorithmSha512withecdsa
i.signAlgo = types.SigningAlgorithmSha512withecdsa
default:
return nil, fmt.Errorf("unsupported CA cert signing algorithm: %T", i.caCert.SignatureAlgorithm)
i.initErr = fmt.Errorf("unsupported CA cert signing algorithm: %T", i.caCert.SignatureAlgorithm)
return
}
})
if i.initErr != nil {
return nil, i.initErr
}

csrPEM, keyPEM, err := csr.FromCertConfig(commonName, conf)
Expand All @@ -99,38 +112,38 @@ func (i Issuer) Issue(ctx context.Context, commonName string, conf *certify.Cert
ttl = int64(i.TimeToLive)
}

csrReq := i.Client.IssueCertificateRequest(&acmpca.IssueCertificateInput{
issueResp, err := i.Client.IssueCertificate(ctx, &acmpca.IssueCertificateInput{
CertificateAuthorityArn: aws.String(i.CertificateAuthorityARN),
Csr: csrPEM,
SigningAlgorithm: i.signAlgo,
Validity: &acmpca.Validity{
Type: acmpca.ValidityPeriodTypeDays,
Validity: &types.Validity{
Type: types.ValidityPeriodTypeDays,
Value: aws.Int64(ttl),
},
})

csrResp, err := csrReq.Send()
if err != nil {
return nil, err
}

getReq := &acmpca.GetCertificateInput{
CertificateArn: csrResp.CertificateArn,
err = i.waiter.Wait(ctx, &acmpca.GetCertificateInput{
CertificateArn: issueResp.CertificateArn,
CertificateAuthorityArn: aws.String(i.CertificateAuthorityARN),
}
err = i.Client.WaitUntilCertificateIssuedWithContext(ctx, getReq)
}, time.Minute)
if err != nil {
return nil, err
}

certReq := i.Client.GetCertificateRequest(getReq)
getReq := &acmpca.GetCertificateInput{
CertificateArn: issueResp.CertificateArn,
CertificateAuthorityArn: aws.String(i.CertificateAuthorityARN),
}

certResp, err := certReq.Send()
cert, err := i.Client.GetCertificate(ctx, getReq)
if err != nil {
return nil, err
}

caChainPEM := append(append([]byte(*certResp.Certificate), '\n'), []byte(*certResp.CertificateChain)...)
caChainPEM := append(append([]byte(*cert.Certificate), '\n'), []byte(*cert.CertificateChain)...)

tlsCert, err := tls.X509KeyPair(caChainPEM, keyPEM)
if err != nil {
Expand Down
13 changes: 0 additions & 13 deletions issuers/aws/aws_suite_test.go

This file was deleted.

Loading

0 comments on commit 14a03e7

Please sign in to comment.