Best practice for checking if desired OIDC Identity Provider already exists during synth #22243
Replies: 4 comments 2 replies
-
This is interesting. You actually can check the existence of a singleton resource with custom resource, but you can't conditionally create a dependent resource based on the condition by reference to an attribute of a custom resource. I actually can't figure out any good practice to make it possible 100% within CDK app. However, you can consider to write a wrapper script to deploy your cdk like this: #!/bin/bash
function check_if_already_exists_function() {
# check the existence with AWS CLI
}
oidcp_exist=$(check_if_already_exists_function)
npx cdk deploy -c oidcp_exist=${oidcp_exist} And you can conditionally create the |
Beta Was this translation helpful? Give feedback.
-
Considering use ssm to store Arn for this. If Arn, just create references from Arn, else create a new one. |
Beta Was this translation helpful? Give feedback.
-
@pahud @ChenKuanSun @LiamGraham I'm facing the same problem that specific resources can only be created once, e.g. a Custom Domain Name for API Gateway. CDK standard behaviour will result in a "The domain name you provided already exists." error when you try to deploy the stack again, e.g. because you made changes, added new API resources or methods, etc. The way I see it, there are basically three ways to handle this: 1) Create the problematic resources using a Lambda backed CustomResourceSince the existence of a specific DomainName can be determined by AWS SDK API calls using the name, e.g. Within a Lambda function of a CustomResource you could check for Pro
Con
2) Wrap the whole stack in async IIFE and check for existing resources with AWS SDK within the CDK stackThis is basically the same approach as 1) but with less overhead. You can wrap your whole stack in an async IFEE like this and use AWS SDK (within your CDK App) to check for the resource existence: export class ApiStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
(async () => {
const api = new apigateway.RestApi(this, `${process.env.STACK_NAME}-${process.env.STACK_ENV}_api`, {
description: 'Customer API',
deployOptions: {
stageName: `${process.env.STACK_ENV}`
},
endpointConfiguration: { types: [EndpointType.REGIONAL] }
});
// check if DomainName exists with AWS SDK
let apiGatewayDomainExists = false;
const sdk_apigw = new sdk.APIGateway();
try {
await sdk_apigw.getDomainName({ domainName: `${process.env.DOMAIN}` }).promise();
apiGatewayDomainExists = true;
console.log(`API Gateway custom domain "${process.env.DOMAIN}" does exist and will NOT be created.`);
} catch (error) {
console.log(`API Gateway custom domain "${process.env.DOMAIN}" does not exist and will be created.`);
}
if (!apiGatewayDomainExists) {
const domainName = new apigateway.DomainName(this, `${process.env.STACK_NAME}-${process.env.STACK_ENV}_domain`, {
domainName: `${process.env.DOMAIN}`,
certificate: Certificate.fromCertificateArn(this, `${process.env.STACK_NAME}-${process.env.STACK_ENV}_cert`, `${process.env.AWS_ACM_CERT_ARN}`),
endpointType: EndpointType.REGIONAL,
mapping: api
});
domainName.applyRemovalPolicy(RemovalPolicy.RETAIN);
new CfnOutput(this, `${process.env.STACK_NAME}-${process.env.STACK_ENV}_api_gateway_domain_name`, { value: domainName.domainNameAliasDomainName });
}
....
})();
}
} Pro
Con
3) Store the CDK state SSM and retrieve / evaluate state when re-deployingFollowing this approach: https://bobbyhadz.com/blog/aws-cdk-ssm-parameters you could store the state (e.g. "DomainNameResourceCreated" in a SSM parameter. The creation itself could depend on the evaluation of that SSM parameter directly in the CDK stack. if(domainNameCreatedParam) {
....
} Pro
Con
I'm using the second approach with async IIFE, since it works well and doesn't introduce overhead. What's your recommendation / approach? Thanks! |
Beta Was this translation helpful? Give feedback.
-
we separate "singleton per account" things in a different stack than for example "stack-per-eks-cluster" items. We use dependency (
when running "cdk ls" we have code that will dynamically look for the various stack types and build the dependency graph. For example, we know that an eks cluster provisioned in account-1 will need to depend on the "account-1 stack". Similarly, the "resources-cluster2" stack will depend on the "cluster2" stack. This will only work if the stacks can live together in the same cdk app. If not, we'd still probably provision the oidc provider as an "account-stack" item, and store any data that needs retrieving in a well-known ssm path so that other apps can retrieve it. We do this for EKS oidc provider arns, which are needed by app stacks to construct the correct iam role trust policy. |
Beta Was this translation helpful? Give feedback.
-
We have a stack that provisions an IAM role used to allow AWS SDK commands to be run from a GitHub workflow. This is facilitated by an OpenID Connect (OIDC) provider configured for our GitHub organisation. This provider is also created as part of this stack. However, it is only possible to create one OIDC provider for a given URL (https://token.actions.githubusercontent.com in this case) per AWS account, and attempting to run this same CDK stack multiple times leads to a deployment error.
This is the code in question:
We would like to be able to first check for the existence of this OIDC provider in our CDK, and only create a new provider if one has not been created previously. As this requires making an async AWS SDK call to retrieve the provider ARN, this is not immediately possible given the constructor-based design of CDK.
What is the recommended best practice for checking for the existence of a singleton resource, such as this OIDC provider, as part of the build process?
Beta Was this translation helpful? Give feedback.
All reactions