aws-quickstart / cdk-eks-blueprints

AWS Quick Start Team
Apache License 2.0
454 stars 205 forks source link

Fargate profiles: Unable to Attach podExecutionRole to Fargate Profile Using Blueprint #1070

Closed saiumesh-appfire closed 2 months ago

saiumesh-appfire commented 2 months ago

Describe the bug

Hello There!!

I’m facing an issue where I cannot attach a podExecutionRole to a Fargate profile because the Blueprint doesn’t allow using the existing stack. This limitation is causing problems in setting up the necessary role for my Fargate profiles.

Example code as follow

new FargateClusterProvider({
    version: KubernetesVersion.V1_29,
    clusterName: `${this.props.clusterName}`,
    fargateProfiles: this.getFargateProfiles(),
    tags: this.props.tags,
});

private getFargateProfiles(): Map<string, FargateProfileOptions> {
    const namespaces = [
        ...this.props.namespaces.map((namespace) => namespace.name),
    ];

    // Issue: How do we correctly obtain the scope here?
    const role = new Role(this.scope, "FargatePodExecutionRole", {});

    return new Map([
        // Observability
        [
            "observability",
            {
                selectors: OBSERVABILITY_NAMESPACES.map((namespace) => ({
                    namespace,
                })),
                podExecutionRole: role,
            },
        ],
    ]);
}

Expected Behavior

We should be able to attach podExecutionRole to the Fargate profiles

Current Behavior

Problem:

The Blueprint setup doesn’t provide a clear way to reference an existing stack’s scope, which is necessary to create and attach the podExecutionRole to a Fargate profile.

Request:

I’m looking for guidance on how to correctly obtain the scope in this context, or if there’s an alternative approach to achieve this.

Reproduction Steps

new FargateClusterProvider({
    version: KubernetesVersion.V1_29,
    clusterName: `${this.props.clusterName}`,
    fargateProfiles: this.getFargateProfiles(),
    tags: this.props.tags,
});

private getFargateProfiles(): Map<string, FargateProfileOptions> {
    const namespaces = [
        ...this.props.namespaces.map((namespace) => namespace.name),
    ];

    // Issue: How do we correctly obtain the scope here?
    const role = new Role(this.scope, "FargatePodExecutionRole", {});

    return new Map([
        // Observability
        [
            "observability",
            {
                selectors: OBSERVABILITY_NAMESPACES.map((namespace) => ({
                    namespace,
                })),
                podExecutionRole: role,
            },
        ],
    ]);
}

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.141.0

EKS Blueprints Version

1.15.1

Node.js Version

v18.16.0

Environment details (OS name and version, etc.)

MacOs

Other information

No response

shapirov103 commented 2 months ago

@saiumesh-appfire There are several ways how you can approach injecting a pod execution role to the FargateClusterProvider.

If your use case is to create a pod execution role and use it with Fargate profile then you can use ResourceProvider, please see https://aws-quickstart.github.io/cdk-eks-blueprints/resource-providers/#using-resource-providers-with-cdk-constructs.

This will allow declarative approach to pass the role using something like this:

const fargateProfiles = {
    dynatrace: {
        selectors: [
            {
                namespace: 'dynatrace',
                labels: { // optional
                    'example.com/fargate': 'true'
                }
            }
        ]
    },
    podExecutionRole: blueprints.getResource(context => { // will generate a unique name for resource. designed for cases when resource is defined once and needed in a single place.
        return new iam.Role(context.scope, 'AdminRole', { assumedBy: new AccountRootPrincipal() });
    })
};

Please also read the overall approach to resource providers here you can use a named resource for more complex cases.

Another option is to just create your own stack and use new EksBlueprintConstruct() inside that stack constructor, this enables you to reuse an existing stack if you already have one. We will create an example for this in the patterns soon as there are some features in the construct that run asynchronously.

You can also create a separate stack for resources and use cross-stack references, the downside is that you will end up with more than one stack.

saiumesh-appfire commented 2 months ago

Thanks, @shapirov103 for your response. We have implemented the suggested solution using getResource and it works great!