Output apikey value in cloud formation

Viewed 2933

I have a cloudformation template that outputs variables. One of the output variable is

 ApiGKeyId:
    Description: "Api Key Id"
    Value: !Ref ApplicationApiGatewayApiKey

This returns the Id of API gateway key and not the actual value. Is there a way to get the value?

3 Answers

attribute "Value" is not supported according to below thread~
https://github.com/awslabs/serverless-application-model/issues/206

3rd party maintained available attributes at a glance here: https://theburningmonk.com/cloudformation-ref-and-getatt-cheatsheet/

After some research, I felt there is no other way to retrieve the ApiKey's value but using Custom Resource invoking an lambda function. Here is my sample code fyr.

#######################################################
##### Start of Custom functions #####
#######################################################
ValueFunc:
  Type: AWS::Lambda::Function
  Properties:
    Code:
      ZipFile: >
        var response = require('cfn-response');
        var AWS = require('aws-sdk');

        exports.handler = function(event, context) {
          var apiKeyID = event.ResourceProperties.ApiKeyID;
          var apigateway = new AWS.APIGateway();
          var params = {
            apiKey: apiKeyID,
            includeValue: true
          };

          apigateway.getApiKey(params, function(err, ApiKeyData) {
            if (err) {
              console.log(err, err.stack); // an error occurred
              var responseData = { "mykey" : "error reading ApiKey" };
              response.send(event, context, response.SUCCESS, responseData);
            } else {
              console.log(ApiKeyData.value);      // successful response
              var responseData = { "mykey" : ApiKeyData.value };
              response.send(event, context, response.SUCCESS, responseData);
            }
          });
        };
    Handler: index.handler
    Runtime: nodejs8.10
    Timeout: 30
    Role: !Sub "arn:aws:iam::${AWS::AccountId}:role/${LambdaExecutionRole}"
GetApiKeyValue:
  Type: Custom::LambdaCallout
  Properties:
    ServiceToken: !GetAtt ValueFunc.Arn
    ApiKeyID: !Ref ApiKey

I had to write a post deployment script that will read the API Key value and insert into dynamodb db table. I have used a combination of bash script and aws console.

# Get the api KeyName from cloudformation output
awsApiGatewayKeyId=$(get_cf_output ApiGKeyName)

# With the name you call get-api-key and pass the KeyName
# When used with include-values it return the API key in the property value
awsApiGatewayKey=$(aws apigateway get-api-keys --name-query $awsApiGatewayKeyId --include-values --query 'items[0].value' --output text )

# Insert the values into Dynamodb for API Authorizer. 
$(aws dynamodb put-item --table-name $tokenAuthTable --item '{"ApiKey": { "S": "'"$awsApiGatewayKey"'" }, "HmacSigningKey":  { "S": "'"$csapiSecretKey"'"},"Name":  { "S": "'"$stackName"'"}}' )

By doing this I didn't have to do any manual task of putting the record in dynamodb.

Please refer this below Url for getting api key. https://docs.aws.amazon.com/cli/latest/reference/apigateway/get-api-key.html

In case anyone is looking to do this in Python with custom resources:

Resources:
  ApiKey:
    Type: AWS::ApiGateway::ApiKey
    Properties:
      Enabled: true
  #######################################################
  ##### Start of Custom functions #####
  #######################################################
  ValueFuncExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      Path: "/"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: apigateway:GET
                Resource: !Sub arn:aws:apigateway:${AWS::Region}::/apikeys/${ApiKey}

  ValueFunc:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: |
          import boto3
          import cfnresponse

          def lambda_handler(event, context):
            response_code = 200
            api_gateway_client = boto3.client('apigateway')
            api_key_id = event['ResourceProperties']['ApiKeyID']
            response = api_gateway_client.get_api_key(
              apiKey=api_key_id,
              includeValue=True
            )
            responseValue = response['value']
            responseData = {}
            responseData['Data'] = responseValue
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID", noEcho=True)
      Handler: index.lambda_handler
      Runtime: python3.9
      Timeout: 30
      Role: !Sub "arn:aws:iam::${AWS::AccountId}:role/${ValueFuncExecutionRole}"
  GetApiKeyValue:
    Type: Custom::LambdaCallout
    Properties:
      ServiceToken: !GetAtt ValueFunc.Arn
      ApiKeyID: !Ref ApiKey

Outputs:
  APIKeyValue:
    Description: "The actual API Key Value"
    Value: !GetAtt GetApiKeyValue.Data
Related