Skip to content

Commit

Permalink
Upgrade to aws-sdk-go-v2 and Go 1.16
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Nguyen committed May 21, 2021
1 parent 667441c commit 93399cc
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 110 deletions.
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
!**/*.go
!**/*.mod
!**/*.sum
./bin/
./testbin/
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.15 as builder
FROM golang:1.16 as builder

WORKDIR /workspace
# Copy the Go Modules manifests
Expand Down
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ module github.com/jniebuhr/aws-pca-issuer
go 1.15

require (
github.com/aws/aws-sdk-go v1.36.25
github.com/aws/aws-sdk-go-v2 v1.5.0
github.com/aws/aws-sdk-go-v2/credentials v1.2.0
github.com/aws/aws-sdk-go-v2/service/acmpca v1.4.0
github.com/aws/aws-sdk-go-v2/service/sts v1.4.0
github.com/go-logr/logr v0.3.0
github.com/jetstack/cert-manager v1.3.1
github.com/stretchr/testify v1.6.1 // indirect
github.com/stretchr/testify v1.6.1
k8s.io/api v0.20.2
k8s.io/apimachinery v0.20.2
k8s.io/client-go v0.20.2
Expand Down
66 changes: 15 additions & 51 deletions go.sum

Large diffs are not rendered by default.

59 changes: 35 additions & 24 deletions pkg/aws/pca.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,31 @@ import (
"encoding/pem"
"fmt"
"sync"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/acmpca"
"github.com/aws/aws-sdk-go/service/acmpca/acmpcaiface"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/acmpca"
acmpcatypes "github.com/aws/aws-sdk-go-v2/service/acmpca/types"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
"k8s.io/apimachinery/pkg/types"
)

var collection = new(sync.Map)

// GenericProvisioner abstracts over the Provisioner type for mocking purposes
type GenericProvisioner interface {
Sign(ctx context.Context, cr *cmapi.CertificateRequest) ([]byte, []byte, error)
}

// acmPCAClient abstracts over the methods used from acmpca.Client
type acmPCAClient interface {
acmpca.GetCertificateAPIClient
IssueCertificate(ctx context.Context, params *acmpca.IssueCertificateInput, optFns ...func(*acmpca.Options)) (*acmpca.IssueCertificateOutput, error)
}

// PCAProvisioner contains logic for issuing PCA certificates
type PCAProvisioner struct {
pcaClient acmpcaiface.ACMPCAAPI
pcaClient acmPCAClient
arn string
}

Expand All @@ -62,9 +69,9 @@ func StoreProvisioner(name types.NamespacedName, provisioner GenericProvisioner)
}

// NewProvisioner returns a new PCAProvisioner
func NewProvisioner(session *session.Session, arn string) (p *PCAProvisioner) {
func NewProvisioner(config aws.Config, arn string) (p *PCAProvisioner) {
return &PCAProvisioner{
pcaClient: acmpca.New(session, &aws.Config{}),
pcaClient: acmpca.NewFromConfig(config),
arn: arn,
}
}
Expand All @@ -91,18 +98,21 @@ func (p *PCAProvisioner) Sign(ctx context.Context, cr *cmapi.CertificateRequest)
validityDays = int64(cr.Spec.Duration.Hours() / 24)
}

// Consider it a "retry" if we try to re-create a cert with the same name in the same namespace
idempotencyToken := cr.ObjectMeta.Namespace + "/" + cr.ObjectMeta.Name

issueParams := acmpca.IssueCertificateInput{
CertificateAuthorityArn: aws.String(p.arn),
SigningAlgorithm: aws.String(sigAlgorithm),
SigningAlgorithm: sigAlgorithm,
Csr: cr.Spec.Request,
Validity: &acmpca.Validity{
Type: aws.String(acmpca.ValidityPeriodTypeDays),
Value: aws.Int64(validityDays),
Validity: &acmpcatypes.Validity{
Type: acmpcatypes.ValidityPeriodTypeDays,
Value: &validityDays,
},
IdempotencyToken: aws.String("awspca"),
IdempotencyToken: &idempotencyToken,
}

issueOutput, err := p.pcaClient.IssueCertificate(&issueParams)
issueOutput, err := p.pcaClient.IssueCertificate(ctx, &issueParams)

if err != nil {
return nil, nil, err
Expand All @@ -113,12 +123,13 @@ func (p *PCAProvisioner) Sign(ctx context.Context, cr *cmapi.CertificateRequest)
CertificateAuthorityArn: aws.String(p.arn),
}

err = p.pcaClient.WaitUntilCertificateIssued(&getParams)
waiter := acmpca.NewCertificateIssuedWaiter(p.pcaClient)
err = waiter.Wait(ctx, &getParams, 5*time.Minute)
if err != nil {
return nil, nil, err
}

getOutput, err := p.pcaClient.GetCertificate(&getParams)
getOutput, err := p.pcaClient.GetCertificate(ctx, &getParams)
if err != nil {
return nil, nil, err
}
Expand All @@ -129,7 +140,7 @@ func (p *PCAProvisioner) Sign(ctx context.Context, cr *cmapi.CertificateRequest)
return certPem, caCertChainPem, nil
}

func signatureAlgorithm(cr *x509.CertificateRequest) (string, error) {
func signatureAlgorithm(cr *x509.CertificateRequest) (acmpcatypes.SigningAlgorithm, error) {
switch cr.PublicKeyAlgorithm {
case x509.RSA:
pubKey, ok := cr.PublicKey.(*rsa.PublicKey)
Expand All @@ -139,13 +150,13 @@ func signatureAlgorithm(cr *x509.CertificateRequest) (string, error) {

switch {
case pubKey.N.BitLen() >= 4096:
return acmpca.SigningAlgorithmSha512withrsa, nil
return acmpcatypes.SigningAlgorithmSha512withrsa, nil
case pubKey.N.BitLen() >= 3072:
return acmpca.SigningAlgorithmSha384withrsa, nil
return acmpcatypes.SigningAlgorithmSha384withrsa, nil
case pubKey.N.BitLen() >= 2048:
return acmpca.SigningAlgorithmSha256withrsa, nil
return acmpcatypes.SigningAlgorithmSha256withrsa, nil
case pubKey.N.BitLen() == 0:
return acmpca.SigningAlgorithmSha256withrsa, nil
return acmpcatypes.SigningAlgorithmSha256withrsa, nil
default:
return "", fmt.Errorf("unsupported rsa keysize specified: %d", pubKey.N.BitLen())
}
Expand All @@ -157,13 +168,13 @@ func signatureAlgorithm(cr *x509.CertificateRequest) (string, error) {

switch pubKey.Curve.Params().BitSize {
case 521:
return acmpca.SigningAlgorithmSha512withecdsa, nil
return acmpcatypes.SigningAlgorithmSha512withecdsa, nil
case 384:
return acmpca.SigningAlgorithmSha384withecdsa, nil
return acmpcatypes.SigningAlgorithmSha384withecdsa, nil
case 256:
return acmpca.SigningAlgorithmSha256withecdsa, nil
return acmpcatypes.SigningAlgorithmSha256withecdsa, nil
case 0:
return acmpca.SigningAlgorithmSha256withecdsa, nil
return acmpcatypes.SigningAlgorithmSha256withecdsa, nil
default:
return "", fmt.Errorf("unsupported ecdsa keysize specified: %d", pubKey.Curve.Params().BitSize)
}
Expand Down
34 changes: 15 additions & 19 deletions pkg/aws/pca_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/service/acmpca"
"github.com/aws/aws-sdk-go/service/acmpca/acmpcaiface"
"github.com/aws/aws-sdk-go-v2/service/acmpca"
"github.com/aws/aws-sdk-go-v2/service/acmpca/types"
v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
"github.com/stretchr/testify/assert"
)
Expand All @@ -49,74 +49,70 @@ var (
)

type errorACMPCAClient struct {
acmpcaiface.ACMPCAAPI
acmPCAClient
}

func (m *errorACMPCAClient) IssueCertificate(input *acmpca.IssueCertificateInput) (*acmpca.IssueCertificateOutput, error) {
func (m *errorACMPCAClient) IssueCertificate(_ context.Context, input *acmpca.IssueCertificateInput, _ ...func(*acmpca.Options)) (*acmpca.IssueCertificateOutput, error) {
return nil, errors.New("Cannot issue certificate")
}

type workingACMPCAClient struct {
acmpcaiface.ACMPCAAPI
acmPCAClient
}

func (m *workingACMPCAClient) IssueCertificate(input *acmpca.IssueCertificateInput) (*acmpca.IssueCertificateOutput, error) {
func (m *workingACMPCAClient) IssueCertificate(_ context.Context, input *acmpca.IssueCertificateInput, _ ...func(*acmpca.Options)) (*acmpca.IssueCertificateOutput, error) {
return &acmpca.IssueCertificateOutput{CertificateArn: &certArn}, nil
}

func (m *workingACMPCAClient) WaitUntilCertificateIssued(input *acmpca.GetCertificateInput) error {
return nil
}

func (m *workingACMPCAClient) GetCertificate(input *acmpca.GetCertificateInput) (*acmpca.GetCertificateOutput, error) {
func (m *workingACMPCAClient) GetCertificate(_ context.Context, input *acmpca.GetCertificateInput, _ ...func(*acmpca.Options)) (*acmpca.GetCertificateOutput, error) {
return &acmpca.GetCertificateOutput{Certificate: &cert, CertificateChain: &chain}, nil
}

func TestPCASignatureAlgorithm(t *testing.T) {
type createKey func() (priv interface{})

type testCase struct {
expectedAlgorithm string
expectedAlgorithm types.SigningAlgorithm
createKeyFun createKey
}
tests := map[string]testCase{
"success-RSA-2048": {
expectedAlgorithm: acmpca.SigningAlgorithmSha256withrsa,
expectedAlgorithm: types.SigningAlgorithmSha256withrsa,
createKeyFun: func() (priv interface{}) {
keyBytes, _ := rsa.GenerateKey(rand.Reader, 2048)
return keyBytes
},
},
"success-RSA-3072": {
expectedAlgorithm: acmpca.SigningAlgorithmSha384withrsa,
expectedAlgorithm: types.SigningAlgorithmSha384withrsa,
createKeyFun: func() (priv interface{}) {
keyBytes, _ := rsa.GenerateKey(rand.Reader, 3072)
return keyBytes
},
},
"success-RSA-4096": {
expectedAlgorithm: acmpca.SigningAlgorithmSha512withrsa,
expectedAlgorithm: types.SigningAlgorithmSha512withrsa,
createKeyFun: func() (priv interface{}) {
keyBytes, _ := rsa.GenerateKey(rand.Reader, 4096)
return keyBytes
},
},
"success-ECDSA-521": {
expectedAlgorithm: acmpca.SigningAlgorithmSha512withecdsa,
expectedAlgorithm: types.SigningAlgorithmSha512withecdsa,
createKeyFun: func() (priv interface{}) {
keyBytes, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
return keyBytes
},
},
"success-ECDSA-384": {
expectedAlgorithm: acmpca.SigningAlgorithmSha384withecdsa,
expectedAlgorithm: types.SigningAlgorithmSha384withecdsa,
createKeyFun: func() (priv interface{}) {
keyBytes, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
return keyBytes
},
},
"success-ECDSA-256": {
expectedAlgorithm: acmpca.SigningAlgorithmSha256withecdsa,
expectedAlgorithm: types.SigningAlgorithmSha256withecdsa,
createKeyFun: func() (priv interface{}) {
keyBytes, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
return keyBytes
Expand All @@ -131,7 +127,7 @@ func TestPCASignatureAlgorithm(t *testing.T) {
response, _ := signatureAlgorithm(csr)

if tc.expectedAlgorithm != response {
assert.Fail(t, "Expected type "+tc.expectedAlgorithm+" but got "+response)
assert.Fail(t, "Expected type %v, but got %s", tc.expectedAlgorithm, response)
}
})
}
Expand Down
6 changes: 2 additions & 4 deletions pkg/controllers/certificaterequest_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import (
"errors"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go-v2/aws"
logrtesting "github.com/go-logr/logr/testing"
cmutil "github.com/jetstack/cert-manager/pkg/api/util"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
Expand Down Expand Up @@ -54,8 +53,7 @@ func (p *fakeProvisioner) Sign(ctx context.Context, cr *cmapi.CertificateRequest
type createMockProvisioner func()

func TestProvisonerOperation(t *testing.T) {
session, _ := session.NewSession(&aws.Config{})
provisioner := awspca.NewProvisioner(session, "arn")
provisioner := awspca.NewProvisioner(aws.Config{}, "arn")
awspca.StoreProvisioner(types.NamespacedName{Namespace: "ns1", Name: "issuer1"}, provisioner)
output, exists := awspca.GetProvisioner(types.NamespacedName{Namespace: "ns1", Name: "issuer1"})
assert.Equal(t, output, provisioner)
Expand Down
17 changes: 8 additions & 9 deletions pkg/controllers/genericissuer_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import (
"fmt"
"os"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/sts"
"github.com/go-logr/logr"
api "github.com/jniebuhr/aws-pca-issuer/pkg/api/v1beta1"
awspca "github.com/jniebuhr/aws-pca-issuer/pkg/aws"
Expand Down Expand Up @@ -73,7 +73,7 @@ func (r *GenericIssuerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
config := aws.Config{}

if spec.Region != "" {
config.Region = aws.String(spec.Region)
config.Region = spec.Region
}

if spec.SecretRef.Name != "" {
Expand Down Expand Up @@ -108,14 +108,13 @@ func (r *GenericIssuerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
config.Credentials = credentials.NewStaticCredentials(string(accessKey), string(secretKey), "")
}

sess, err := session.NewSession(&config)
id, err := sts.NewFromConfig(config).GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{})
if err != nil {
log.Error(err, "failed to create AWS session")
_ = r.setStatus(ctx, issuer, metav1.ConditionFalse, "Error", "Failed to create AWS session")
log.Error(err, "failed to sts.GetCallerIdentity")
return ctrl.Result{}, err
}

awspca.StoreProvisioner(req.NamespacedName, awspca.NewProvisioner(sess, spec.Arn))
log.Info("sts.GetCallerIdentity", "arn", id.Arn, "account", id.Account, "user_id", id.UserId)
awspca.StoreProvisioner(req.NamespacedName, awspca.NewProvisioner(config, spec.Arn))

return ctrl.Result{}, r.setStatus(ctx, issuer, metav1.ConditionTrue, "Verified", "Issuer verified")
}
Expand Down

0 comments on commit 93399cc

Please sign in to comment.