Reputation: 428
I'm unable to find out how to get the api key out of an apigateway key. I can get its ID and its ARN but not the value. I know you can specify the value when creating the key, but not how to retrieve it once created--short of logging into the AWS GUI and finding it that way.
I've looked at the documentation for aws-apigateway.ApiKey and couldn't find any way to get the value. https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.ApiKey.html I've also looked at kms keys since you can get their value, but I don't know if it's usable in the context of an API Gateway usage plan (not included in code below).
Failing the ability to get the value, is there a way to generate a value that won't change, or will persist? I'm using an ephemeral Jenkins node to run the CDK.
const apiGateway = require('@aws-cdk/aws-apigateway');
...
const apiKey = new apiGateway.ApiKey(this, 'api-key', {
apiKeyName: 'my-api-key',
});
...
new cdk.CfnOutput(this, 'x-api-key-apiKey_id', {
value: apiKey.keyId
});
new cdk.CfnOutput(this, 'x-api-key-apiKey_keyArn', {
value: apiKey.keyArn
});
Upvotes: 7
Views: 8438
Reputation: 473
Python version of @ishan-jain's solution:
class GetApiKeyCr(Construct):
def __init__(self, scope: Stack, id: str, api_key: aws_apigateway.IApiKey):
self.apikey_value: str
super().__init__(scope, id)
api_key_details: custom_resources.AwsSdkCall = custom_resources.AwsSdkCall(
service="APIGateway",
action="getApiKey",
parameters={
"apiKey": api_key.key_id,
"includeValue": True,
},
physical_resource_id=custom_resources.PhysicalResourceId.of(
f"APIKey:{api_key.key_id}"
),
)
api_key_cr = custom_resources.AwsCustomResource(
self,
"api-key-cr",
policy=custom_resources.AwsCustomResourcePolicy.from_statements(
[
aws_iam.PolicyStatement(
effect=aws_iam.Effect.ALLOW,
resources=[api_key.key_arn],
actions=["apigateway:GET"],
),
]
),
log_retention=aws_logs.RetentionDays.ONE_DAY,
on_create=api_key_details,
on_update=api_key_details,
)
api_key_cr.node.add_dependency(api_key)
self.apikey_value = api_key_cr.get_response_field("value")
Upvotes: 0
Reputation: 765
The accepted answer is perhaps not the best way to go about this. It can be solved without creating an extra secret using aws-cdk's custom resources.
Here is a snippet that will get you the value of an api key. The value of this key is generated randomly by the api gateway.
import * as iam from "@aws-cdk/aws-iam";
import { RetentionDays } from "@aws-cdk/aws-logs";
import * as cdk from "@aws-cdk/core";
import {
AwsCustomResource,
AwsCustomResourcePolicy,
AwsSdkCall,
PhysicalResourceId,
} from "@aws-cdk/custom-resources";
import { IApiKey } from "@aws-cdk/aws-apigateway";
export interface GetApiKeyCrProps {
apiKey: IApiKey;
}
export class GetApiKeyCr extends cdk.Construct {
apikeyValue: string;
constructor(scope: cdk.Construct, id: string, props: GetApiKeyCrProps) {
super(scope, id);
const apiKey: AwsSdkCall = {
service: "APIGateway",
action: "getApiKey",
parameters: {
apiKey: props.apiKey.keyId,
includeValue: true,
},
physicalResourceId: PhysicalResourceId.of(`APIKey:${props.apiKey.keyId}`),
};
const apiKeyCr = new AwsCustomResource(this, "api-key-cr", {
policy: AwsCustomResourcePolicy.fromStatements([
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [props.apiKey.keyArn],
actions: ["apigateway:GET"],
}),
]),
logRetention: RetentionDays.ONE_DAY,
onCreate: apiKey,
onUpdate: apiKey,
});
apiKeyCr.node.addDependency(props.apiKey);
this.apikeyValue = apiKeyCr.getResponseField("value");
}
}
Upvotes: 4
Reputation: 428
I'm going to use https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SecretsManager.html#getRandomPassword-property to generate the 20 characters and set the API key. Since nothing outside of my stack needs the key I'm ok with regenerating it and updating my resources every time I do a deploy. However if there are things outside of the stack that need the key then using Balu's answer is the best option.
The reason for this is keeping a secret has a cost associated with it.
Upvotes: 1
Reputation: 10333
We can't retrieve the auto generated key via cdk/cloudformation without a custom resource. But we can generate the key , store it in a secret manager or an ssm secret and use that to create api key.
const secret = new secretsmanager.Secret(this, 'Secret', {
generateSecretString: {
generateStringKey: 'api_key',
secretStringTemplate: JSON.stringify({ username: 'web_user' }),
excludeCharacters: ' %+~`#$&*()|[]{}:;<>?!\'/@"\\',
},
});
this.restApi.addApiKey('ApiKey', {
apiKeyName: `web-app-key`,
value: secret.secretValueFromJson('api_key').toString(),
});
Upvotes: 10