How to rotate IAM Access Keys which were created using AWS CDK

Viewed 74

We have a IAM User Access Key created via CDK using CfnAccessKey construct.

However, this access key hasn't been rotated for more than 90 days so we want to rotate it, but through CDK only with minimal interruption and effort each time going forward.

Is there any way to achieve that via AWS CDK?

1 Answers

You need to setup CfnAccessKey or aws_iam.AccessKey construct serial props in order to setup rotation. Everytime you need to rotate, just increment the serial value to inform cloudformation for rotation

According to Docs

This value is specific to CloudFormation and can only be incremented . Incrementing this value notifies CloudFormation that you want to rotate your access key. When you update your stack, CloudFormation will replace the existing access key with a new key.

During instantiation

// The code below shows an example of how to instantiate this type.
// The values are placeholders you should change.
import * as iam from '@aws-cdk/aws-iam';
const cfnAccessKey = new iam.CfnAccessKey(this, 'MyCfnAccessKey', {
  userName: 'userName',

  // the properties below are optional
  serial: 1,
  status: 'Active',
});

For rotating keys

// The code below shows an example of how to instantiate this type.
// The values are placeholders you should change.
import * as iam from '@aws-cdk/aws-iam';
const cfnAccessKey = new iam.CfnAccessKey(this, 'MyCfnAccessKey', {
  userName: 'userName',

  // the properties below are optional
  serial: 2,
  status: 'Active',
});

Update 1) using L2 construct (aws_iam.AccessKey)

import { CfnOutput, Duration, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { aws_iam as iam } from 'aws-cdk-lib';
import { AccessKeyStatus, User } from 'aws-cdk-lib/aws-iam';


export class CdkStackoverflowStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const existingUserFromName = User.fromUserName(this, 'user-from-name-id', 'cdk-stackoverflow')
    const cfnAccessKey = new iam.AccessKey(this, 'MyCfnAccessKey', {
      user: existingUserFromName,
      // the properties below are optional
      serial: 2,
      status: AccessKeyStatus.ACTIVE,
    })
    new CfnOutput(this, 'accessSecretKey', { value: cfnAccessKey.secretAccessKey.unsafeUnwrap().toString() })
    new CfnOutput(this, 'accessKeyID', { value: cfnAccessKey.accessKeyId.toString() })
  }
}

Update 2:- [ as per comments] Keys created with cdk without serial value

Created user from console called as cdk-stakcoverflow without access key. Created access key from CDK without setting serial value. observe the comments

 export class CdkStackoverflowStack extends Stack {
      constructor(scope: Construct, id: string, props?: StackProps) {
        super(scope, id, props);
        const existingUserFromName = User.fromUserName(this, 'user-from-name-id', 'cdk-stackoverflow')
        const cfnAccessKey = new iam.AccessKey(this, 'MyCfnAccessKey', {
          user: existingUserFromName,
          // the properties below are optional
          // serial: 5,
          // status: AccessKeyStatus.ACTIVE,
        })
        new CfnOutput(this, 'accessSecretKey', { value: cfnAccessKey.secretAccessKey.unsafeUnwrap().toString() })
        new CfnOutput(this, 'accessKeyID', { value: cfnAccessKey.accessKeyId.toString() })
      }
    }

Take a note of ID either from console or terminal Now uncomment the serial line, and redeploy the stack, you will see that your key is updated, atleast in my environment this is being rotated :)

 export class CdkStackoverflowStack extends Stack {
      constructor(scope: Construct, id: string, props?: StackProps) {
        super(scope, id, props);
        const existingUserFromName = User.fromUserName(this, 'user-from-name-id', 'cdk-stackoverflow')
        const cfnAccessKey = new iam.AccessKey(this, 'MyCfnAccessKey', {
          user: existingUserFromName,
          // the properties below are optional
          serial: 5,
          status: AccessKeyStatus.ACTIVE,
        })
        new CfnOutput(this, 'accessSecretKey', { value: cfnAccessKey.secretAccessKey.unsafeUnwrap().toString() })
        new CfnOutput(this, 'accessKeyID', { value: cfnAccessKey.accessKeyId.toString() })
      }
    }

Note :- you don't need to Output access keys its just for sure confirmation that keys added by cdk is added, you can delete your existing key which is not managed by cdk.

Related