diff --git a/pkg/model/iam/subject.go b/pkg/model/iam/subject.go index ab61c6704b..4103f76ffd 100644 --- a/pkg/model/iam/subject.go +++ b/pkg/model/iam/subject.go @@ -108,7 +108,7 @@ func addServiceAccountRoleForAWS(context *IAMModelContext, podSpec *corev1.PodSp return err } - awsRoleARN := "arn:aws:iam::" + context.AWSAccountID + ":role/" + roleName + awsRoleARN := "arn:" + context.AWSPartition + ":iam::" + context.AWSAccountID + ":role/" + roleName tokenDir := "/var/run/secrets/amazonaws.com/" tokenName := "token" diff --git a/pkg/model/iam/types.go b/pkg/model/iam/types.go index 5feb634a00..91f07338d2 100644 --- a/pkg/model/iam/types.go +++ b/pkg/model/iam/types.go @@ -35,6 +35,8 @@ func ParseStatements(policy string) ([]*Statement, error) { type IAMModelContext struct { // AWSAccountID holds the 12 digit AWS account ID, when running on AWS AWSAccountID string + // AWSPartition defines the partition of the AWS account, typically "aws", "aws-cn", or "aws-us-gov" + AWSPartition string Cluster *kops.Cluster } diff --git a/upup/pkg/fi/cloudup/apply_cluster.go b/upup/pkg/fi/cloudup/apply_cluster.go index 1575e24cac..2537593a5c 100644 --- a/upup/pkg/fi/cloudup/apply_cluster.go +++ b/upup/pkg/fi/cloudup/apply_cluster.go @@ -408,11 +408,12 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error { awsCloud := cloud.(awsup.AWSCloud) region = awsCloud.Region() - accountID, err := awsCloud.AccountID() + accountID, partition, err := awsCloud.AccountInfo() if err != nil { return err } modelContext.AWSAccountID = accountID + modelContext.AWSPartition = partition if len(sshPublicKeys) == 0 && c.Cluster.Spec.SSHKeyName == nil { return fmt.Errorf("SSH public key must be specified when running with AWS (create with `kops create secret --name %s sshpublickey admin -i ~/.ssh/id_rsa.pub`)", cluster.ObjectMeta.Name) diff --git a/upup/pkg/fi/cloudup/awsup/BUILD.bazel b/upup/pkg/fi/cloudup/awsup/BUILD.bazel index b125f5853c..252c73769e 100644 --- a/upup/pkg/fi/cloudup/awsup/BUILD.bazel +++ b/upup/pkg/fi/cloudup/awsup/BUILD.bazel @@ -29,6 +29,7 @@ go_library( "//protokube/pkg/etcd:go_default_library", "//upup/pkg/fi:go_default_library", "//vendor/github.com/aws/aws-sdk-go/aws:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/aws/arn:go_default_library", "//vendor/github.com/aws/aws-sdk-go/aws/awserr:go_default_library", "//vendor/github.com/aws/aws-sdk-go/aws/client:go_default_library", "//vendor/github.com/aws/aws-sdk-go/aws/endpoints:go_default_library", diff --git a/upup/pkg/fi/cloudup/awsup/aws_cloud.go b/upup/pkg/fi/cloudup/awsup/aws_cloud.go index 6afd2fa046..ff18398bd1 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/aws_cloud.go @@ -24,6 +24,7 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" @@ -163,8 +164,8 @@ type AWSCloud interface { // FindClusterStatus gets the status of the cluster as it exists in AWS, inferred from volumes FindClusterStatus(cluster *kops.Cluster) (*kops.ClusterStatus, error) - // AccountID returns the AWS account ID (typically a 12 digit number) we are deploying into - AccountID() (string, error) + // AccountInfo returns the AWS account ID and AWS partition that we are deploying into + AccountInfo() (string, string, error) } type awsCloudImplementation struct { @@ -1660,19 +1661,25 @@ func describeInstanceType(c AWSCloud, instanceType string) (*ec2.InstanceTypeInf return resp.InstanceTypes[0], nil } -// AccountID returns the AWS account ID (typically a 12 digit number) we are deploying into -func (c *awsCloudImplementation) AccountID() (string, error) { +// AccountInfo returns the AWS account ID and AWS partition that we are deploying into +func (c *awsCloudImplementation) AccountInfo() (string, string, error) { request := &sts.GetCallerIdentityInput{} response, err := c.sts.GetCallerIdentity(request) if err != nil { - return "", fmt.Errorf("error geting AWS account ID: %v", err) + return "", "", fmt.Errorf("error geting AWS account ID: %v", err) } - account := aws.StringValue(response.Account) - if account == "" { - return "", fmt.Errorf("AWS account id was empty") + arn, err := arn.Parse(aws.StringValue(response.Arn)) + if err != nil { + return "", "", fmt.Errorf("Failed to parse GetCallerIdentity ARN") } - return account, nil + if arn.AccountID == "" { + return "", "", fmt.Errorf("AWS account id was empty") + } + if arn.Partition == "" { + return "", "", fmt.Errorf("AWS partition was empty") + } + return arn.AccountID, arn.Partition, nil } diff --git a/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go b/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go index d44fa956f4..220d55a4ff 100644 --- a/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go @@ -301,7 +301,7 @@ func (c *MockAWSCloud) DescribeInstanceType(instanceType string) (*ec2.InstanceT return info, nil } -// AccountID returns the AWS account ID (typically a 12 digit number) we are deploying into -func (c *MockAWSCloud) AccountID() (string, error) { - return "123456789012", nil +// AccountInfo returns the AWS account ID and AWS partition that we are deploying into +func (c *MockAWSCloud) AccountInfo() (string, string, error) { + return "123456789012", "aws-test", nil } diff --git a/upup/pkg/fi/cloudup/bootstrapchannelbuilder_test.go b/upup/pkg/fi/cloudup/bootstrapchannelbuilder_test.go index eaf282bf1e..5c0a84086e 100644 --- a/upup/pkg/fi/cloudup/bootstrapchannelbuilder_test.go +++ b/upup/pkg/fi/cloudup/bootstrapchannelbuilder_test.go @@ -111,6 +111,7 @@ func runChannelBuilderTest(t *testing.T, key string, addonManifests []string) { IAMModelContext: iam.IAMModelContext{ Cluster: cluster, AWSAccountID: "123456789012", + AWSPartition: "aws-test", }, Region: "us-east-1", InstanceGroups: []*kopsapi.InstanceGroup{ diff --git a/upup/pkg/fi/cloudup/tests/bootstrapchannelbuilder/public-jwks/dns-controller.addons.k8s.io-k8s-1.12.yaml b/upup/pkg/fi/cloudup/tests/bootstrapchannelbuilder/public-jwks/dns-controller.addons.k8s.io-k8s-1.12.yaml index f8ddbf272f..749befbf1e 100644 --- a/upup/pkg/fi/cloudup/tests/bootstrapchannelbuilder/public-jwks/dns-controller.addons.k8s.io-k8s-1.12.yaml +++ b/upup/pkg/fi/cloudup/tests/bootstrapchannelbuilder/public-jwks/dns-controller.addons.k8s.io-k8s-1.12.yaml @@ -35,7 +35,7 @@ spec: - name: KUBERNETES_SERVICE_HOST value: 127.0.0.1 - name: AWS_ROLE_ARN - value: arn:aws:iam::123456789012:role/dns-controller.kube-system.sa.minimal.example.com + value: arn:aws-test:iam::123456789012:role/dns-controller.kube-system.sa.minimal.example.com - name: AWS_WEB_IDENTITY_TOKEN_FILE value: /var/run/secrets/amazonaws.com/token image: k8s.gcr.io/kops/dns-controller:1.19.0-alpha.4 diff --git a/upup/pkg/fi/cloudup/tests/bootstrapchannelbuilder/public-jwks/manifest.yaml b/upup/pkg/fi/cloudup/tests/bootstrapchannelbuilder/public-jwks/manifest.yaml index 90282862b7..4cf22d55ee 100644 --- a/upup/pkg/fi/cloudup/tests/bootstrapchannelbuilder/public-jwks/manifest.yaml +++ b/upup/pkg/fi/cloudup/tests/bootstrapchannelbuilder/public-jwks/manifest.yaml @@ -73,7 +73,7 @@ spec: - id: k8s-1.12 kubernetesVersion: '>=1.12.0' manifest: dns-controller.addons.k8s.io/k8s-1.12.yaml - manifestHash: ec9465805a830d1029d3fb7a181202a1f9266b8e + manifestHash: 749f5c0750966f8d6ef79090796c1d9c7688edb4 name: dns-controller.addons.k8s.io selector: k8s-addon: dns-controller.addons.k8s.io