Skip to content

Commit dd775d8

Browse files
hc-github-team-consul-coreManishakumari-hcanilvpatel
authored
Backport of migrate to aws-sdk-go-v2 into release/1.22.x (#23225)
* backport of commit c59dbc2 * fix: punctuation in changelog --------- Co-authored-by: Manisha Kumari <manisha.kumari@hashicorp.com> Co-authored-by: anilvpatel <anilkumarvinodbhai.patel@hashicorp.com>
1 parent ba05bd5 commit dd775d8

11 files changed

Lines changed: 941 additions & 228 deletions

File tree

.changelog/23109.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
```release-note:improvement
2+
connect: Migrate to aws-sdk-go-v2 from aws-sdk-go (v1). Also updated consul-awsauth and go-secure-stdlib/awsutil dependencies to their v2 versions.
3+
cli: Added `--aws-iam-endpoint` flag to `consul login` command for AWS IAM auth method to support custom IAM endpoint configuration.
4+
```

agent/connect/ca/provider_aws.go

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@ package ca
55

66
import (
77
"bytes"
8+
"context"
89
"crypto/x509"
910
"encoding/pem"
11+
"errors"
1012
"fmt"
1113
"sync/atomic"
1214
"time"
1315

14-
"github.com/aws/aws-sdk-go/aws"
15-
"github.com/aws/aws-sdk-go/aws/awserr"
16-
"github.com/aws/aws-sdk-go/aws/session"
17-
"github.com/aws/aws-sdk-go/service/acmpca"
16+
"github.com/aws/aws-sdk-go-v2/aws"
17+
awsconfig "github.com/aws/aws-sdk-go-v2/config"
18+
"github.com/aws/aws-sdk-go-v2/service/acmpca"
19+
"github.com/aws/aws-sdk-go-v2/service/acmpca/types"
20+
"github.com/aws/smithy-go"
1821

1922
"github.com/go-viper/mapstructure/v2"
2023
"github.com/hashicorp/go-hclog"
@@ -65,8 +68,8 @@ type AWSProvider struct {
6568
stopCh chan struct{}
6669

6770
config *structs.AWSCAProviderConfig
68-
session *session.Session
69-
client *acmpca.ACMPCA
71+
awsConfig *aws.Config
72+
client *acmpca.Client
7073
isPrimary bool
7174
datacenter string
7275
clusterID string
@@ -99,19 +102,19 @@ func (a *AWSProvider) Configure(cfg ProviderConfig) error {
99102
// another place or sending them via API call and persisting them in state
100103
// store in a new place on disk. One of the existing standard solutions seems
101104
// better in all cases.
102-
awsSession, err := session.NewSessionWithOptions(session.Options{
103-
SharedConfigState: session.SharedConfigEnable,
104-
})
105+
awsConfig, err := awsconfig.LoadDefaultConfig(context.Background(),
106+
awsconfig.WithSharedConfigProfile(""),
107+
)
105108
if err != nil {
106109
return err
107110
}
108111

109112
a.config = config
110-
a.session = awsSession
113+
a.awsConfig = &awsConfig
111114
a.isPrimary = cfg.IsPrimary
112115
a.clusterID = cfg.ClusterID
113116
a.datacenter = cfg.Datacenter
114-
a.client = acmpca.New(awsSession)
117+
a.client = acmpca.NewFromConfig(awsConfig)
115118
a.stopCh = make(chan struct{})
116119

117120
// Load the ARN from config or previous state.
@@ -171,14 +174,14 @@ func (a *AWSProvider) ensureCA() error {
171174
input := &acmpca.DescribeCertificateAuthorityInput{
172175
CertificateAuthorityArn: aws.String(a.arn),
173176
}
174-
output, err := a.client.DescribeCertificateAuthority(input)
177+
output, err := a.client.DescribeCertificateAuthority(context.Background(), input)
175178
if err != nil {
176179
return err
177180
}
178181
// Allow it to be active or pending a certificate (leadership might have
179182
// changed during a secondary initialization for example).
180-
if *output.CertificateAuthority.Status != acmpca.CertificateAuthorityStatusActive &&
181-
*output.CertificateAuthority.Status != acmpca.CertificateAuthorityStatusPendingCertificate {
183+
if output.CertificateAuthority.Status != types.CertificateAuthorityStatusActive &&
184+
output.CertificateAuthority.Status != types.CertificateAuthorityStatusPendingCertificate {
182185
verb := "configured"
183186
if a.caCreated {
184187
verb = "created"
@@ -189,7 +192,7 @@ func (a *AWSProvider) ensureCA() error {
189192
// but this is simpler and less surprising default behavior if user
190193
// disabled a CA due to a security concern and we just work around it.
191194
return fmt.Errorf("the %s PCA is not active: status is %s", verb,
192-
*output.CertificateAuthority.Status)
195+
output.CertificateAuthority.Status)
193196
}
194197

195198
// Load the certs
@@ -233,7 +236,7 @@ func (a *AWSProvider) ensureCA() error {
233236
}
234237

235238
a.logger.Debug("uploading certificate for ARN", "arn", a.arn)
236-
_, err = a.client.ImportCertificateAuthorityCertificate(&input)
239+
_, err = a.client.ImportCertificateAuthorityCertificate(context.Background(), &input)
237240
if err != nil {
238241
return err
239242
}
@@ -247,9 +250,9 @@ func keyTypeToAlgos(keyType string, keyBits int) (string, string, error) {
247250
case "rsa":
248251
switch keyBits {
249252
case 2048:
250-
return acmpca.KeyAlgorithmRsa2048, acmpca.SigningAlgorithmSha256withrsa, nil
253+
return string(types.KeyAlgorithmRsa2048), string(types.SigningAlgorithmSha256withrsa), nil
251254
case 4096:
252-
return acmpca.KeyAlgorithmRsa4096, acmpca.SigningAlgorithmSha256withrsa, nil
255+
return string(types.KeyAlgorithmRsa4096), string(types.SigningAlgorithmSha256withrsa), nil
253256
default:
254257
return "", "", fmt.Errorf("AWS PCA only supports RSA key lengths 2048"+
255258
" and 4096, PrivateKeyBits of %d configured", keyBits)
@@ -258,7 +261,7 @@ func keyTypeToAlgos(keyType string, keyBits int) (string, string, error) {
258261
if keyBits != 256 {
259262
return "", "", fmt.Errorf("AWS PCA only supports P256 EC curve, keyBits of %d configured", keyBits)
260263
}
261-
return acmpca.KeyAlgorithmEcPrime256v1, acmpca.SigningAlgorithmSha256withecdsa, nil
264+
return string(types.KeyAlgorithmEcPrime256v1), string(types.SigningAlgorithmSha256withecdsa), nil
262265
default:
263266
return "", "", fmt.Errorf("AWS PCA only supports P256 EC curve, or RSA"+
264267
" 2048/4096. %s, %d configured", keyType, keyBits)
@@ -268,7 +271,7 @@ func keyTypeToAlgos(keyType string, keyBits int) (string, string, error) {
268271
func (a *AWSProvider) createPCA() error {
269272
pcaType := "ROOT" // For some reason there is no constant for this in the SDK
270273
if !a.isPrimary {
271-
pcaType = acmpca.CertificateAuthorityTypeSubordinate
274+
pcaType = string(types.CertificateAuthorityTypeSubordinate)
272275
}
273276

274277
keyAlg, signAlg, err := keyTypeToAlgos(a.config.PrivateKeyType, a.config.PrivateKeyBits)
@@ -283,32 +286,32 @@ func (a *AWSProvider) createPCA() error {
283286
commonName := connect.CACN("aws", uid, a.clusterID, a.isPrimary)
284287

285288
createInput := acmpca.CreateCertificateAuthorityInput{
286-
CertificateAuthorityType: aws.String(pcaType),
287-
CertificateAuthorityConfiguration: &acmpca.CertificateAuthorityConfiguration{
288-
Subject: &acmpca.ASN1Subject{
289+
CertificateAuthorityType: types.CertificateAuthorityType(pcaType),
290+
CertificateAuthorityConfiguration: &types.CertificateAuthorityConfiguration{
291+
Subject: &types.ASN1Subject{
289292
CommonName: aws.String(commonName),
290293
},
291-
KeyAlgorithm: aws.String(keyAlg),
292-
SigningAlgorithm: aws.String(signAlg),
294+
KeyAlgorithm: types.KeyAlgorithm(keyAlg),
295+
SigningAlgorithm: types.SigningAlgorithm(signAlg),
293296
},
294-
RevocationConfiguration: &acmpca.RevocationConfiguration{
297+
RevocationConfiguration: &types.RevocationConfiguration{
295298
// TODO support CRL in future when we manage revocation in Connect more
296299
// generally.
297-
CrlConfiguration: &acmpca.CrlConfiguration{
300+
CrlConfiguration: &types.CrlConfiguration{
298301
Enabled: aws.Bool(false),
299302
},
300303
},
301304
// uid is unique to each PCA we create so use it as an idempotency string. We
302305
// don't actually retry on failure yet but might as well!
303306
IdempotencyToken: aws.String(uid),
304-
Tags: []*acmpca.Tag{
307+
Tags: []types.Tag{
305308
{Key: aws.String("consul_cluster_id"), Value: aws.String(a.clusterID)},
306309
{Key: aws.String("consul_datacenter"), Value: aws.String(a.datacenter)},
307310
},
308311
}
309312

310313
a.logger.Debug("creating new PCA", "common_name", commonName)
311-
createOutput, err := a.client.CreateCertificateAuthority(&createInput)
314+
createOutput, err := a.client.CreateCertificateAuthority(context.Background(), &createInput)
312315
if err != nil {
313316
a.logger.Error("failed to create new PCA", "common_name", commonName, "error", err)
314317
return err
@@ -320,13 +323,14 @@ func (a *AWSProvider) createPCA() error {
320323
CertificateAuthorityArn: aws.String(newARN),
321324
}
322325
_, err = a.pollLoop("Private CA", AWSCreateTimeout, func() (bool, string, error) {
323-
describeOutput, err := a.client.DescribeCertificateAuthority(&describeInput)
326+
describeOutput, err := a.client.DescribeCertificateAuthority(context.Background(), &describeInput)
324327
if err != nil {
325-
if err.(awserr.Error).Code() != acmpca.ErrCodeRequestInProgressException {
328+
var apiErr smithy.APIError
329+
if errors.As(err, &apiErr) && apiErr.ErrorCode() != "RequestInProgressException" {
326330
return true, "", fmt.Errorf("error waiting for PCA to be created: %s", err)
327331
}
328332
}
329-
if *describeOutput.CertificateAuthority.Status == acmpca.CertificateAuthorityStatusPendingCertificate {
333+
if describeOutput.CertificateAuthority.Status == types.CertificateAuthorityStatusPendingCertificate {
330334
a.logger.Debug("new PCA is ready to accept a certificate", "pca", newARN)
331335
a.arn = newARN
332336
// We don't need to reload this ARN since we just created it and know what
@@ -345,7 +349,7 @@ func (a *AWSProvider) getCACSR() (string, error) {
345349
CertificateAuthorityArn: aws.String(a.arn),
346350
}
347351
a.logger.Debug("retrieving CSR for PCA", "pca", a.arn)
348-
output, err := a.client.GetCertificateAuthorityCsr(input)
352+
output, err := a.client.GetCertificateAuthorityCsr(context.Background(), input)
349353
if err != nil {
350354
return "", err
351355
}
@@ -362,7 +366,7 @@ func (a *AWSProvider) loadCACerts() error {
362366
input := &acmpca.GetCertificateAuthorityCertificateInput{
363367
CertificateAuthorityArn: aws.String(a.arn),
364368
}
365-
output, err := a.client.GetCertificateAuthorityCertificate(input)
369+
output, err := a.client.GetCertificateAuthorityCertificate(context.Background(), input)
366370
if err != nil {
367371
return err
368372
}
@@ -458,24 +462,23 @@ func (a *AWSProvider) signCSR(csrPEM string, templateARN string, ttl time.Durati
458462
issueInput := acmpca.IssueCertificateInput{
459463
CertificateAuthorityArn: aws.String(a.arn),
460464
Csr: []byte(csrPEM),
461-
SigningAlgorithm: aws.String(signAlg),
465+
SigningAlgorithm: types.SigningAlgorithm(signAlg),
462466
TemplateArn: aws.String(templateARN),
463-
Validity: &acmpca.Validity{
467+
Validity: &types.Validity{
464468
Value: aws.Int64(int64(ttl / day)),
465-
Type: aws.String(acmpca.ValidityPeriodTypeDays),
469+
Type: types.ValidityPeriodTypeDays,
466470
},
467471
}
468472

469-
issueOutput, err := a.client.IssueCertificate(&issueInput)
473+
issueOutput, err := a.client.IssueCertificate(context.Background(), &issueInput)
470474
// ErrCodeLimitExceededException is used for both hard and soft limits in AWS
471475
// SDK :(. In this specific context though (issuing a certificate) there is no
472476
// hard limit on number of certs so a limit exceeded here is a rate limit.
473-
if aerr, ok := err.(awserr.Error); ok && err != nil {
474-
if aerr.Code() == acmpca.ErrCodeLimitExceededException {
477+
if err != nil {
478+
var apiErr smithy.APIError
479+
if errors.As(err, &apiErr) && apiErr.ErrorCode() == "LimitExceededException" {
475480
return "", ErrRateLimited
476481
}
477-
}
478-
if err != nil {
479482
return "", fmt.Errorf("error issuing certificate from PCA: %s", err)
480483
}
481484

@@ -487,9 +490,10 @@ func (a *AWSProvider) signCSR(csrPEM string, templateARN string, ttl time.Durati
487490
return a.pollLoop(fmt.Sprintf("certificate %s", *issueOutput.CertificateArn),
488491
AWSSignTimeout,
489492
func() (bool, string, error) {
490-
certOutput, err := a.client.GetCertificate(&certInput)
493+
certOutput, err := a.client.GetCertificate(context.Background(), &certInput)
491494
if err != nil {
492-
if err.(awserr.Error).Code() != acmpca.ErrCodeRequestInProgressException {
495+
var apiErr smithy.APIError
496+
if errors.As(err, &apiErr) && apiErr.ErrorCode() != "RequestInProgressException" {
493497
return true, "", fmt.Errorf("error retrieving certificate from PCA: %s", err)
494498
}
495499
}
@@ -533,7 +537,7 @@ func (a *AWSProvider) SetIntermediate(intermediatePEM string, rootPEM string, _
533537
CertificateChain: []byte(rootPEM),
534538
}
535539
a.logger.Debug("uploading certificate for PCA", "pca", a.arn)
536-
_, err = a.client.ImportCertificateAuthorityCertificate(&input)
540+
_, err = a.client.ImportCertificateAuthorityCertificate(context.Background(), &input)
537541
if err != nil {
538542
return err
539543
}
@@ -611,10 +615,10 @@ func (a *AWSProvider) disablePCA() error {
611615
}
612616
input := acmpca.UpdateCertificateAuthorityInput{
613617
CertificateAuthorityArn: aws.String(a.arn),
614-
Status: aws.String(acmpca.CertificateAuthorityStatusDisabled),
618+
Status: types.CertificateAuthorityStatusDisabled,
615619
}
616620
a.logger.Info("disabling PCA", "pca", a.arn)
617-
_, err := a.client.UpdateCertificateAuthority(&input)
621+
_, err := a.client.UpdateCertificateAuthority(context.Background(), &input)
618622
return err
619623
}
620624

@@ -626,10 +630,10 @@ func (a *AWSProvider) deletePCA() error {
626630
CertificateAuthorityArn: aws.String(a.arn),
627631
// We only ever use this to clean up after tests so delete as quickly as
628632
// possible (7 days).
629-
PermanentDeletionTimeInDays: aws.Int64(7),
633+
PermanentDeletionTimeInDays: aws.Int32(7),
630634
}
631635
a.logger.Info("deleting PCA", "pca", a.arn)
632-
_, err := a.client.DeleteCertificateAuthority(&input)
636+
_, err := a.client.DeleteCertificateAuthority(context.Background(), &input)
633637
return err
634638
}
635639

0 commit comments

Comments
 (0)