1

I'm creating EKS cluster using AWS CDK. I want to assigned clustername as per the environment. We have prefix for each environment in SSM parameter. I'm trying to specifiy cluster name as follows:

First step- fetch prefix:

const clusternamevalue = ssm.StringParameter.fromStringParameterAttributes(this, 'clustername', {
     parameterName:'environment-identifier-short'
    } ).stringValue

Second step- create cluster:

new eks.Cluster(this, 'cluster', {
      version: eks.KubernetesVersion.V1_19,
      clusterName: 'eks-'.concat(clusternamevalue),
    });

But cluster is not getting created and throws message in Cloudformation: Respective role<rolearn> is not authorized to perform: eks:CreateCluster on resource <ClusterARN>

On checking Cfn template I see that the policy to create cluster is getting created in below way:

Resource": [
                {
                  "Fn::Join": [
                    "",
                    [
                      "arn:",
                      {
                        "Ref": "AWS::Partition"
                      },
                      ":eks:eu-west-1:XXXXXXXXX:cluster/[object Object]"
                    ]
                  ]
                },

I think due to [object object] part , policy is not getting created with correct cluster name. Hence it getting failed. if we hardcode clustername, it will work.

Any suggestion, how i solve this issue? or how i can explicitly pass the role while creating cluster?

Vikas Banage
  • 494
  • 1
  • 8
  • 25
  • 1
    Can you mention in the question which language you're using. And also print `clusternamevalue` when you fetch it. Make sure it's correct data type when fetched. – Hussain Mansoor Jan 18 '22 at 11:26
  • 1
    Its typescript. clusternamevalue is coming correctly. I think policy which is not getting created correctly with required clusternamevalue. – Vikas Banage Jan 18 '22 at 12:21
  • 1
    This smells like a possible CDK bug. Does the template resource `Custom::AWSCDK-EKS-Cluster`'s `Config.name` property have a proper `"Fn::Join"` value? – fedonev Jan 18 '22 at 13:03
  • 1
    @fedonev I did a synth on the above code in CDK v2.8.0 and got the same issue. The Config.name has a proper value but the IAM role policies have [object Object] – Kaustubh Khavnekar Jan 18 '22 at 16:24

1 Answers1

1

TL;DR It's the CDK's fault. The CDK cannot generate ARNs for the admin role policies if clusterName is part-string and part-token. The workaround is to add the policies manually.

The OP code looks fine.* CDK is correctly parsing 'eks-'.concat(clusternamevalue) as the clusterName (thanks, @KaustubhKhavnekar!), but is incorrectly parsing the name when it creates the cluster admin role. The problematic CDK code is here, where it creates the role resource ARNs on the cluster:

export class ClusterResource extends CoreConstruct {
  ...
  private createAdminRole(props: ClusterResourceProps)
    ...
    const resourceArns = Lazy.list({
      produce: () => {
        const arn = stack.formatArn(
          clusterArnComponents(stack.resolve(props.name))  // does not like string + token name!
        );
        return stack.resolve(props.name) ? [arn, `${arn}/*`] : ['*'];
      },
    });

Not sure what the root cause is. A workaround is to manually add policy statements with good ARNs to the admin role, like the custom resource is doing under the hood:

// manually add policies with the correct cluster ARN to the cluster's adminRole

const clusterArn = this.formatArn({
  service: 'eks',
  resource: 'cluster',
  resourceName: clusternamevalue,
});

cluster.adminRole.addToPolicy(
  new iam.PolicyStatement({
    actions: [
      'eks:CreateCluster',
      'eks:DescribeCluster',
      'eks:DescribeUpdate',
      'eks:DeleteCluster',
      'eks:UpdateClusterVersion',
      'eks:UpdateClusterConfig',
      'eks:CreateFargateProfile',
      'eks:TagResource',
      'eks:UntagResource',
    ],
    resources: [clusterArn, clusterArn + '/*'],
  })
);

const fargateProfileArn = this.formatArn({
  service: 'eks',
  resource: 'fargateprofile',
  resourceName: clusternamevalue,
});

cluster.adminRole.addToPolicy(
  new iam.PolicyStatement({
    actions: ['eks:DescribeFargateProfile', 'eks:DeleteFargateProfile'],
    resources: [fargateProfileArn],
  })
);

* CDK usually handles string-token interpolation without problem, but to be sure I tried manually creating the resourceName value with cdk.Fn.join('', ['eks-', param.stringValue]) and cdk.Sub. No luck - same result.

fedonev
  • 20,327
  • 2
  • 25
  • 34