diff --git a/cloudmock/aws/mockiam/iaminstanceprofile.go b/cloudmock/aws/mockiam/iaminstanceprofile.go index c88a62c91fe43..4ae303cde608e 100644 --- a/cloudmock/aws/mockiam/iaminstanceprofile.go +++ b/cloudmock/aws/mockiam/iaminstanceprofile.go @@ -31,8 +31,8 @@ func (m *MockIAM) GetInstanceProfile(ctx context.Context, request *iam.GetInstan m.mutex.Lock() defer m.mutex.Unlock() - ip, ok := m.InstanceProfiles[aws.ToString(request.InstanceProfileName)] - if !ok || strings.Contains(aws.ToString(ip.InstanceProfileName), "__no_entity__") { + ip := m.InstanceProfiles[aws.ToString(request.InstanceProfileName)] + if ip == nil || strings.Contains(aws.ToString(ip.InstanceProfileName), "__no_entity__") { return nil, &iamtypes.NoSuchEntityException{} } response := &iam.GetInstanceProfileOutput{ @@ -83,8 +83,8 @@ func (m *MockIAM) TagInstanceProfile(ctx context.Context, request *iam.TagInstan klog.Infof("CreateInstanceProfile: %v", request) - ip, ok := m.InstanceProfiles[aws.ToString(request.InstanceProfileName)] - if !ok { + ip := m.InstanceProfiles[aws.ToString(request.InstanceProfileName)] + if ip == nil { return nil, fmt.Errorf("InstanceProfile not found") } @@ -111,13 +111,13 @@ func (m *MockIAM) AddRoleToInstanceProfile(ctx context.Context, request *iam.Add klog.Infof("AddRoleToInstanceProfile: %v", request) - ip, ok := m.InstanceProfiles[aws.ToString(request.InstanceProfileName)] - if !ok { - return nil, fmt.Errorf("InstanceProfile not found") + ip := m.InstanceProfiles[aws.ToString(request.InstanceProfileName)] + if ip == nil { + return nil, fmt.Errorf("instance profile not found") } - r, ok := m.Roles[aws.ToString(request.RoleName)] - if !ok { - return nil, fmt.Errorf("Role not found") + r := m.Roles[aws.ToString(request.RoleName)] + if r == nil { + return nil, fmt.Errorf("role not found") } ip.Roles = append(ip.Roles, *r) @@ -131,9 +131,9 @@ func (m *MockIAM) RemoveRoleFromInstanceProfile(ctx context.Context, request *ia klog.Infof("RemoveRoleFromInstanceProfile: %v", request) - ip, ok := m.InstanceProfiles[aws.ToString(request.InstanceProfileName)] - if !ok { - return nil, fmt.Errorf("InstanceProfile not found") + ip := m.InstanceProfiles[aws.ToString(request.InstanceProfileName)] + if ip == nil { + return nil, fmt.Errorf("instance profile not found") } found := false @@ -147,7 +147,7 @@ func (m *MockIAM) RemoveRoleFromInstanceProfile(ctx context.Context, request *ia } if !found { - return nil, fmt.Errorf("Role not found") + return nil, fmt.Errorf("role not found") } ip.Roles = newRoles @@ -185,8 +185,8 @@ func (m *MockIAM) DeleteInstanceProfile(ctx context.Context, request *iam.Delete klog.Infof("DeleteInstanceProfile: %v", request) id := aws.ToString(request.InstanceProfileName) - _, ok := m.InstanceProfiles[id] - if !ok { + o := m.InstanceProfiles[id] + if o == nil { return nil, fmt.Errorf("InstanceProfile %q not found", id) } delete(m.InstanceProfiles, id) diff --git a/cloudmock/aws/mockiam/iamrole.go b/cloudmock/aws/mockiam/iamrole.go index f8143b6211495..ca584f04df0c6 100644 --- a/cloudmock/aws/mockiam/iamrole.go +++ b/cloudmock/aws/mockiam/iamrole.go @@ -30,8 +30,8 @@ func (m *MockIAM) GetRole(ctx context.Context, request *iam.GetRoleInput, optFns m.mutex.Lock() defer m.mutex.Unlock() - role, ok := m.Roles[aws.ToString(request.RoleName)] - if !ok { + role := m.Roles[aws.ToString(request.RoleName)] + if role == nil { return nil, &iamtypes.NoSuchEntityException{} } response := &iam.GetRoleOutput{ @@ -97,9 +97,9 @@ func (m *MockIAM) DeleteRole(ctx context.Context, request *iam.DeleteRoleInput, klog.Infof("DeleteRole: %v", request) id := aws.ToString(request.RoleName) - _, ok := m.Roles[id] - if !ok { - return nil, fmt.Errorf("Role %q not found", id) + o := m.Roles[id] + if o == nil { + return nil, fmt.Errorf("role %q not found", id) } delete(m.Roles, id) diff --git a/cloudmock/aws/mockiam/oidcprovider.go b/cloudmock/aws/mockiam/oidcprovider.go index 1a43822b7bffe..e0cd5c1ef589e 100644 --- a/cloudmock/aws/mockiam/oidcprovider.go +++ b/cloudmock/aws/mockiam/oidcprovider.go @@ -93,8 +93,8 @@ func (m *MockIAM) DeleteOpenIDConnectProvider(ctx context.Context, request *iam. klog.Infof("DeleteOpenIDConnectProvider: %v", request) arn := aws.ToString(request.OpenIDConnectProviderArn) - _, ok := m.OIDCProviders[arn] - if !ok { + provider := m.OIDCProviders[arn] + if provider == nil { return nil, fmt.Errorf("OIDCProvider %q not found", arn) } delete(m.OIDCProviders, arn) diff --git a/go.mod b/go.mod index dae7f9c717171..8d54e8858a979 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0 github.com/aws/aws-sdk-go-v2/service/sqs v1.31.4 github.com/aws/aws-sdk-go-v2/service/ssm v1.49.5 + github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 github.com/aws/smithy-go v1.20.2 github.com/blang/semver/v4 v4.0.0 github.com/cert-manager/cert-manager v1.14.4 @@ -120,7 +121,6 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.4 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect diff --git a/pkg/model/awsmodel/iam.go b/pkg/model/awsmodel/iam.go index b5f47ed40845c..044be0e85121f 100644 --- a/pkg/model/awsmodel/iam.go +++ b/pkg/model/awsmodel/iam.go @@ -21,7 +21,7 @@ import ( "sort" "strings" - awsIam "github.com/aws/aws-sdk-go-v2/service/iam" + awsiam "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go/aws/endpoints" "k8s.io/apimachinery/pkg/types" "k8s.io/klog/v2" @@ -476,9 +476,8 @@ func (b *IAMModelBuilder) FindDeletions(context *fi.CloudupModelBuilderContext, ctx := context.Context() iamapi := cloud.(awsup.AWSCloud).IAM() ownershipTag := "kubernetes.io/cluster/" + b.Cluster.ObjectMeta.Name - request := &awsIam.ListRolesInput{} - var getRoleErr error - paginator := awsIam.NewListRolesPaginator(iamapi, request) + request := &awsiam.ListRolesInput{} + paginator := awsiam.NewListRolesPaginator(iamapi, request) for paginator.HasMorePages() { page, err := paginator.NextPage(ctx) if err != nil { @@ -488,7 +487,7 @@ func (b *IAMModelBuilder) FindDeletions(context *fi.CloudupModelBuilderContext, if !strings.HasSuffix(fi.ValueOf(role.RoleName), "."+b.Cluster.ObjectMeta.Name) { continue } - getRequest := &awsIam.GetRoleInput{RoleName: role.RoleName} + getRequest := &awsiam.GetRoleInput{RoleName: role.RoleName} roleOutput, err := iamapi.GetRole(ctx, getRequest) if err != nil { return fmt.Errorf("calling IAM GetRole on %s: %w", fi.ValueOf(role.RoleName), err) @@ -506,8 +505,5 @@ func (b *IAMModelBuilder) FindDeletions(context *fi.CloudupModelBuilderContext, } } } - if getRoleErr != nil { - return getRoleErr - } return nil } diff --git a/pkg/resources/aws/aws.go b/pkg/resources/aws/aws.go index 4f0ace08b1894..5181d9728896f 100644 --- a/pkg/resources/aws/aws.go +++ b/pkg/resources/aws/aws.go @@ -33,7 +33,6 @@ import ( "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/route53" - "github.com/aws/smithy-go" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/klog/v2" "k8s.io/kops/pkg/dns" @@ -1844,16 +1843,13 @@ func DeleteIAMRole(cloud fi.Cloud, r *resources.Resource) error { for paginator.HasMorePages() { page, err := paginator.NextPage(ctx) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { klog.V(2).Infof("Got NoSuchEntity describing IAM RolePolicy %q; will treat as already-deleted", roleName) return nil } return fmt.Errorf("error listing IAM role policies for %q: %v", roleName, err) } - for _, policy := range page.PolicyNames { - policyNames = append(policyNames, policy) - } + policyNames = append(policyNames, page.PolicyNames...) } } @@ -1866,8 +1862,7 @@ func DeleteIAMRole(cloud fi.Cloud, r *resources.Resource) error { for paginator.HasMorePages() { page, err := paginator.NextPage(ctx) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { klog.V(2).Infof("Got NoSuchEntity describing IAM RolePolicy %q; will treat as already-deleted", roleName) return nil } @@ -1939,12 +1934,11 @@ func ListIAMRoles(cloud fi.Cloud, vpcID, clusterName string) ([]*resources.Resou getRequest := &iam.GetRoleInput{RoleName: r.RoleName} roleOutput, err := c.IAM().GetRole(ctx, getRequest) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { - klog.Warningf("could not find role %q. Resource may already have been deleted: %v", name, nse) + if awsup.IsIAMNoSuchEntityException(err) { + klog.Warningf("could not find role %q. Resource may already have been deleted: %v", name, err) continue - } else if awserror, ok := err.(smithy.APIError); ok && awserror.ErrorCode() == "403" { - klog.Warningf("failed to determine ownership of %q: %v", name, awserror) + } else if awsup.AWSErrorCode(err) == "403" { + klog.Warningf("failed to determine ownership of %q: %v", name, err) continue } return nil, fmt.Errorf("calling IAM GetRole on %s: %w", name, err) @@ -2024,12 +2018,11 @@ func ListIAMInstanceProfiles(cloud fi.Cloud, vpcID, clusterName string) ([]*reso getRequest := &iam.GetInstanceProfileInput{InstanceProfileName: p.InstanceProfileName} profileOutput, err := c.IAM().GetInstanceProfile(ctx, getRequest) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { - klog.Warningf("could not find role %q. Resource may already have been deleted: %v", name, nse) + if awsup.IsIAMNoSuchEntityException(err) { + klog.Warningf("could not find role %q. Resource may already have been deleted: %v", name, err) continue - } else if awserror, ok := err.(smithy.APIError); ok && awserror.ErrorCode() == "403" { - klog.Warningf("failed to determine ownership of %q: %v", *p.InstanceProfileName, awserror) + } else if awsup.AWSErrorCode(err) == "403" { + klog.Warningf("failed to determine ownership of %q: %v", *p.InstanceProfileName, err) continue } return nil, fmt.Errorf("calling IAM GetInstanceProfile on %s: %w", name, err) @@ -2080,12 +2073,11 @@ func ListIAMOIDCProviders(cloud fi.Cloud, vpcID, clusterName string) ([]*resourc } resp, err := c.IAM().GetOpenIDConnectProvider(ctx, descReq) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { - klog.Warningf("could not find IAM OIDC Provider %q. Resource may already have been deleted: %v", aws.StringValue(arn), nse) + if awsup.IsIAMNoSuchEntityException(err) { + klog.Warningf("could not find IAM OIDC Provider %q. Resource may already have been deleted: %v", aws.StringValue(arn), err) continue - } else if awserror, ok := err.(smithy.APIError); ok && awserror.ErrorCode() == "403" { - klog.Warningf("failed to determine ownership of %q: %v", aws.StringValue(arn), awserror) + } else if awsup.AWSErrorCode(err) == "403" { + klog.Warningf("failed to determine ownership of %q: %v", aws.StringValue(arn), err) continue } return nil, fmt.Errorf("error getting IAM OIDC Provider %q: %w", aws.StringValue(arn), err) @@ -2123,8 +2115,7 @@ func DeleteIAMOIDCProvider(cloud fi.Cloud, r *resources.Resource) error { } _, err := c.IAM().DeleteOpenIDConnectProvider(ctx, request) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { klog.V(2).Infof("Got NoSuchEntity deleting IAM OIDC Provider %v; will treat as already-deleted", arn) return nil } diff --git a/upup/pkg/fi/cloudup/apply_cluster.go b/upup/pkg/fi/cloudup/apply_cluster.go index 414c343a93c77..757c943040268 100644 --- a/upup/pkg/fi/cloudup/apply_cluster.go +++ b/upup/pkg/fi/cloudup/apply_cluster.go @@ -427,7 +427,7 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error { { awsCloud := cloud.(awsup.AWSCloud) - accountID, partition, err := awsCloud.AccountInfo() + accountID, partition, err := awsCloud.AccountInfo(ctx) if err != nil { return err } diff --git a/upup/pkg/fi/cloudup/awstasks/iaminstanceprofile.go b/upup/pkg/fi/cloudup/awstasks/iaminstanceprofile.go index f99a15c2d1ce9..4e5a6bff7a372 100644 --- a/upup/pkg/fi/cloudup/awstasks/iaminstanceprofile.go +++ b/upup/pkg/fi/cloudup/awstasks/iaminstanceprofile.go @@ -18,7 +18,6 @@ package awstasks import ( "context" - "errors" "fmt" "k8s.io/kops/upup/pkg/fi" @@ -55,8 +54,7 @@ func findIAMInstanceProfile(ctx context.Context, cloud awsup.AWSCloud, name stri request := &iam.GetInstanceProfileInput{InstanceProfileName: aws.String(name)} response, err := cloud.IAM().GetInstanceProfile(ctx, request) - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { return nil, nil } diff --git a/upup/pkg/fi/cloudup/awstasks/iaminstanceprofilerole.go b/upup/pkg/fi/cloudup/awstasks/iaminstanceprofilerole.go index 9cfc999526c5e..b77a9bce93118 100644 --- a/upup/pkg/fi/cloudup/awstasks/iaminstanceprofilerole.go +++ b/upup/pkg/fi/cloudup/awstasks/iaminstanceprofilerole.go @@ -18,12 +18,10 @@ package awstasks import ( "context" - "errors" "fmt" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/iam" - iamtypes "github.com/aws/aws-sdk-go-v2/service/iam/types" "k8s.io/klog/v2" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/cloudup/awsup" @@ -53,8 +51,7 @@ func (e *IAMInstanceProfileRole) Find(c *fi.CloudupContext) (*IAMInstanceProfile request := &iam.GetInstanceProfileInput{InstanceProfileName: e.InstanceProfile.Name} response, err := cloud.IAM().GetInstanceProfile(ctx, request) - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { return nil, nil } diff --git a/upup/pkg/fi/cloudup/awstasks/iamrole.go b/upup/pkg/fi/cloudup/awstasks/iamrole.go index 54443103384c4..5bd3452168836 100644 --- a/upup/pkg/fi/cloudup/awstasks/iamrole.go +++ b/upup/pkg/fi/cloudup/awstasks/iamrole.go @@ -19,7 +19,6 @@ package awstasks import ( "context" "encoding/json" - "errors" "fmt" "net/url" "reflect" @@ -69,8 +68,7 @@ func (e *IAMRole) Find(c *fi.CloudupContext) (*IAMRole, error) { request := &iam.GetRoleInput{RoleName: e.Name} response, err := cloud.IAM().GetRole(ctx, request) - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { return nil, nil } if err != nil { @@ -171,16 +169,13 @@ func (_ *IAMRole) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *IAMRole) error for paginator.HasMorePages() { page, err := paginator.NextPage(ctx) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { klog.V(2).Infof("Got NoSuchEntity describing IAM RolePolicy; will treat as already-deleted") return nil } return fmt.Errorf("error listing IAM role policies: %v", err) } - for _, policy := range page.PolicyNames { - policyNames = append(policyNames, policy) - } + policyNames = append(policyNames, page.PolicyNames...) } } @@ -193,8 +188,7 @@ func (_ *IAMRole) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *IAMRole) error for paginator.HasMorePages() { page, err := paginator.NextPage(ctx) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { klog.V(2).Infof("Got NoSuchEntity describing IAM RolePolicy; will treat as already-deleted") return nil } diff --git a/upup/pkg/fi/cloudup/awstasks/iamrolepolicy.go b/upup/pkg/fi/cloudup/awstasks/iamrolepolicy.go index a33c4cebceaa6..1bdfc094bca3a 100644 --- a/upup/pkg/fi/cloudup/awstasks/iamrolepolicy.go +++ b/upup/pkg/fi/cloudup/awstasks/iamrolepolicy.go @@ -19,7 +19,6 @@ package awstasks import ( "context" "encoding/json" - "errors" "fmt" "hash/fnv" "net/url" @@ -28,7 +27,6 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/iam" - iamtypes "github.com/aws/aws-sdk-go-v2/service/iam/types" "k8s.io/klog/v2" "k8s.io/kops/pkg/diff" "k8s.io/kops/upup/pkg/fi" @@ -68,8 +66,7 @@ func (e *IAMRolePolicy) Find(c *fi.CloudupContext) (*IAMRolePolicy, error) { response, err := cloud.IAM().ListAttachedRolePolicies(ctx, request) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { klog.V(2).Infof("Got NoSuchEntity describing IAM RolePolicy; will treat as already-deleted") return nil, nil } @@ -102,8 +99,7 @@ func (e *IAMRolePolicy) Find(c *fi.CloudupContext) (*IAMRolePolicy, error) { response, err := cloud.IAM().GetRolePolicy(ctx, request) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { return nil, nil } return nil, fmt.Errorf("error getting role: %v", err) @@ -238,8 +234,7 @@ func (_ *IAMRolePolicy) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *IAMRoleP klog.V(2).Infof("Deleting role policy %s/%s", aws.ToString(e.Role.Name), aws.ToString(e.Name)) _, err = t.Cloud.IAM().DeleteRolePolicy(ctx, request) if err != nil { - var nse *iamtypes.NoSuchEntityException - if errors.As(err, &nse) { + if awsup.IsIAMNoSuchEntityException(err) { klog.V(2).Infof("Got NoSuchEntity deleting role policy %s/%s; assuming does not exist", aws.ToString(e.Role.Name), aws.ToString(e.Name)) return nil } diff --git a/upup/pkg/fi/cloudup/awsup/aws_cloud.go b/upup/pkg/fi/cloudup/awsup/aws_cloud.go index d7d13d7ef6e1a..afedf53c4b89d 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/aws_cloud.go @@ -34,11 +34,13 @@ import ( "github.com/aws/aws-sdk-go-v2/aws/arn" "github.com/aws/aws-sdk-go-v2/aws/retry" + stscredsv2 "github.com/aws/aws-sdk-go-v2/credentials/stscreds" elb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" elbtypes "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing/types" elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/credentials/stscreds" @@ -50,7 +52,6 @@ import ( "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/aws/aws-sdk-go/service/route53" "github.com/aws/aws-sdk-go/service/route53/route53iface" - "github.com/aws/aws-sdk-go/service/sts" "k8s.io/klog/v2" v1 "k8s.io/api/core/v1" @@ -191,7 +192,7 @@ type AWSCloud interface { DescribeInstanceType(instanceType string) (*ec2.InstanceTypeInfo, error) // AccountInfo returns the AWS account ID and AWS partition that we are deploying into - AccountInfo() (string, string, error) + AccountInfo(ctx context.Context) (string, string, error) } type awsCloudImplementation struct { @@ -202,7 +203,7 @@ type awsCloudImplementation struct { autoscaling *autoscaling.AutoScaling route53 *route53.Route53 spotinst spotinst.Cloud - sts *sts.STS + sts *sts.Client sqs *sqs.Client eventbridge *eventbridge.Client ssm *ssm.Client @@ -295,16 +296,13 @@ func NewAWSCloud(region string, tags map[string]string) (AWSCloud, error) { }, } - cfgV2, err := awsconfig.LoadDefaultConfig(ctx, + loadOptions := []func(*awsconfig.LoadOptions) error{ awsconfig.WithRegion(region), awsconfig.WithClientLogMode(awsv2.LogRetries), awsconfig.WithLogger(awsLogger{}), awsconfig.WithRetryer(func() awsv2.Retryer { return retry.NewStandard() }), - ) - if err != nil { - return c, fmt.Errorf("failed to load default aws config: %w", err) } config := aws.NewConfig().WithRegion(region) @@ -323,6 +321,15 @@ func NewAWSCloud(region string, tags map[string]string) (AWSCloud, error) { // assumes the role before executing commands roleARN := os.Getenv("KOPS_AWS_ROLE_ARN") if roleARN != "" { + cfgV2, err := awsconfig.LoadDefaultConfig(ctx, loadOptions...) + if err != nil { + return c, fmt.Errorf("failed to load default aws config: %w", err) + } + stsClient := sts.NewFromConfig(cfgV2) + assumeRoleProvider := stscredsv2.NewAssumeRoleProvider(stsClient, roleARN) + + loadOptions = append(loadOptions, awsconfig.WithCredentialsProvider(assumeRoleProvider)) + creds := stscreds.NewCredentials(sess, roleARN) config = &aws.Config{Credentials: creds} config = setConfig(config).WithRegion(region) @@ -332,20 +339,15 @@ func NewAWSCloud(region string, tags map[string]string) (AWSCloud, error) { c.ec2.Handlers.Send.PushFront(requestLogger) c.addHandlers(region, &c.ec2.Handlers) + cfgV2, err := awsconfig.LoadDefaultConfig(ctx, loadOptions...) + if err != nil { + return c, fmt.Errorf("failed to load default aws config: %w", err) + } + c.iam = iam.NewFromConfig(cfgV2) c.elb = elb.NewFromConfig(cfgV2) c.elbv2 = elbv2.NewFromConfig(cfgV2) - - sess, err = session.NewSessionWithOptions(session.Options{ - Config: *config, - SharedConfigState: session.SharedConfigEnable, - }) - if err != nil { - return c, err - } - c.sts = sts.New(sess, config) - c.sts.Handlers.Send.PushFront(requestLogger) - c.addHandlers(region, &c.sts.Handlers) + c.sts = sts.NewFromConfig(cfgV2) sess, err = session.NewSessionWithOptions(session.Options{ Config: *config, @@ -2407,17 +2409,17 @@ func describeInstanceType(c AWSCloud, instanceType string) (*ec2.InstanceTypeInf } // AccountInfo returns the AWS account ID and AWS partition that we are deploying into -func (c *awsCloudImplementation) AccountInfo() (string, string, error) { +func (c *awsCloudImplementation) AccountInfo(ctx context.Context) (string, string, error) { request := &sts.GetCallerIdentityInput{} - response, err := c.sts.GetCallerIdentity(request) + response, err := c.sts.GetCallerIdentity(ctx, request) if err != nil { return "", "", fmt.Errorf("error getting AWS account ID: %v", err) } arn, err := arn.Parse(aws.StringValue(response.Arn)) if err != nil { - return "", "", fmt.Errorf("Failed to parse GetCallerIdentity ARN") + return "", "", fmt.Errorf("failed to parse GetCallerIdentity ARN: %w", err) } if arn.AccountID == "" { diff --git a/upup/pkg/fi/cloudup/awsup/aws_utils.go b/upup/pkg/fi/cloudup/awsup/aws_utils.go index 89c92441f35d2..3e1de9db8debd 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_utils.go +++ b/upup/pkg/fi/cloudup/awsup/aws_utils.go @@ -18,6 +18,7 @@ package awsup import ( "context" + "errors" "fmt" "os" "strings" @@ -30,10 +31,12 @@ import ( ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" elbtypes "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing/types" elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" + iamtypes "github.com/aws/aws-sdk-go-v2/service/iam/types" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/smithy-go" "k8s.io/klog/v2" "k8s.io/kops/pkg/apis/kops" "k8s.io/kops/pkg/truncate" @@ -152,19 +155,25 @@ func FindELBV2Tag(tags []elbv2types.Tag, key string) (string, bool) { return "", false } -// AWSErrorCode returns the aws error code, if it is an awserr.Error, otherwise "" +// AWSErrorCode returns the aws error code, if it is an awserr.Error or smithy.APIError, otherwise "" func AWSErrorCode(err error) string { if awsError, ok := err.(awserr.Error); ok { return awsError.Code() } + if awserror, ok := err.(smithy.APIError); ok { + return awserror.ErrorCode() + } return "" } -// AWSErrorMessage returns the aws error message, if it is an awserr.Error, otherwise "" +// AWSErrorMessage returns the aws error message, if it is an awserr.Error or smithy.APIError, otherwise "" func AWSErrorMessage(err error) string { if awsError, ok := err.(awserr.Error); ok { return awsError.Message() } + if awserror, ok := err.(smithy.APIError); ok { + return awserror.ErrorMessage() + } return "" } @@ -236,3 +245,11 @@ func NameForExternalTargetGroup(targetGroupARN string) (string, error) { } return resource[1], nil } + +func IsIAMNoSuchEntityException(err error) bool { + if err == nil { + return false + } + var nse *iamtypes.NoSuchEntityException + return errors.As(err, &nse) +} diff --git a/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go b/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go index 01c0348743aa3..a934a00098efa 100644 --- a/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go @@ -387,7 +387,7 @@ func (c *MockAWSCloud) DescribeInstanceType(instanceType string) (*ec2.InstanceT } // AccountInfo returns the AWS account ID and AWS partition that we are deploying into -func (c *MockAWSCloud) AccountInfo() (string, string, error) { +func (c *MockAWSCloud) AccountInfo(ctx context.Context) (string, string, error) { return "123456789012", "aws-test", nil }