-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(iam): add L2 AccessKey resource
This adds an L2 resource for creating IAM access keys. Instructions for creating access keys are added to the README near the information on creating users. Tests are added (including an integration test) and locations elsewhere in the CDK where `CfnAccessKey` was used have been updated to leverage the new L2 construct (which required changes in the `secretsmanager` and `apigatewayv2-authorizers` packages). Excludes were added for two `awslint` rules. Access Keys don't support specifying physical names, so having such a property is impossible. Additionally, since the primary value of an `AWS::IAM::AccessKey` is to gain access to the `SecretAccessKey` value, a `fromXXX` static method doesn't seem to make a lot of sense (because ideally you'd just pull that from a Secret anyway if it was required in the app).
- Loading branch information
Showing
13 changed files
with
250 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { IResource, Resource } from '@aws-cdk/core'; | ||
import { Construct } from 'constructs'; | ||
import { CfnAccessKey } from './iam.generated'; | ||
import { IUser } from './user'; | ||
|
||
/** | ||
* Valid statuses for an IAM Access Key. | ||
*/ | ||
export enum AccessKeyStatus { | ||
/** | ||
* An active access key. An active key can be used to make API calls. | ||
*/ | ||
ACTIVE = 'Active', | ||
|
||
/** | ||
* An inactive access key. An inactive key cannot be used to make API calls. | ||
*/ | ||
INACTIVE = 'Inactive' | ||
} | ||
|
||
/** | ||
* Represents an IAM Access Key. | ||
* | ||
* @see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html | ||
*/ | ||
export interface IAccessKey extends IResource { | ||
/** | ||
* The Access Key ID. | ||
* | ||
* @attribute | ||
*/ | ||
readonly accessKeyId: string; | ||
|
||
/** | ||
* The Secret Access Key. | ||
* | ||
* @attribute | ||
*/ | ||
readonly secretAccessKey: string; | ||
} | ||
|
||
/** | ||
* Properties for defining an IAM access key. | ||
*/ | ||
export interface AccessKeyProps { | ||
/** | ||
* A CloudFormation-specific value that signifies the access key should be | ||
* replaced/rotated. This value can only be incremented. Incrementing this | ||
* value will cause CloudFormation to replace the Access Key resource. | ||
* | ||
* @default - No serial value | ||
*/ | ||
readonly serial?: number; | ||
|
||
/** | ||
* The status of the access key. An Active access key is allowed to be used | ||
* to make API calls; An Inactive key cannot. | ||
* | ||
* @default - The access key is active | ||
*/ | ||
readonly status?: AccessKeyStatus; | ||
|
||
/** | ||
* The IAM user this key will belong to. | ||
* | ||
* Changing this value will result in the access key being deleted and a new | ||
* access key (with a different ID and secret value) being assigned to the new | ||
* user. | ||
*/ | ||
readonly user: IUser; | ||
} | ||
|
||
/** | ||
* Define a new IAM Access Key. | ||
*/ | ||
export class AccessKey extends Resource implements IAccessKey { | ||
public readonly accessKeyId: string; | ||
public readonly secretAccessKey: string; | ||
|
||
constructor(scope: Construct, id: string, props: AccessKeyProps) { | ||
super(scope, id); | ||
const accessKey = new CfnAccessKey(this, 'Resource', { | ||
userName: props.user.userName, | ||
serial: props.serial, | ||
status: props.status, | ||
}); | ||
|
||
this.accessKeyId = accessKey.ref; | ||
this.secretAccessKey = accessKey.attrSecretAccessKey; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import '@aws-cdk/assert-internal/jest'; | ||
import { App, Stack } from '@aws-cdk/core'; | ||
import { AccessKey, AccessKeyStatus, User } from '../lib'; | ||
|
||
describe('IAM Access keys', () => { | ||
test('user name is identifed via reference', () => { | ||
// GIVEN | ||
const app = new App(); | ||
const stack = new Stack(app, 'MyStack'); | ||
const user = new User(stack, 'MyUser'); | ||
|
||
// WHEN | ||
new AccessKey(stack, 'MyAccessKey', { user }); | ||
|
||
// THEN | ||
expect(stack).toMatchTemplate({ | ||
Resources: { | ||
MyUserDC45028B: { | ||
Type: 'AWS::IAM::User', | ||
}, | ||
MyAccessKeyF0FFBE2E: { | ||
Type: 'AWS::IAM::AccessKey', | ||
Properties: { | ||
UserName: { Ref: 'MyUserDC45028B' }, | ||
}, | ||
}, | ||
}, | ||
}); | ||
}); | ||
|
||
test('active status is specified with correct capitalization', () => { | ||
// GIVEN | ||
const app = new App(); | ||
const stack = new Stack(app, 'MyStack'); | ||
const user = new User(stack, 'MyUser'); | ||
|
||
// WHEN | ||
new AccessKey(stack, 'MyAccessKey', { user, status: AccessKeyStatus.ACTIVE }); | ||
|
||
// THEN | ||
expect(stack).toHaveResourceLike('AWS::IAM::AccessKey', { Status: 'Active' }); | ||
}); | ||
|
||
test('inactive status is specified with correct capitalization', () => { | ||
// GIVEN | ||
const app = new App(); | ||
const stack = new Stack(app, 'MyStack'); | ||
const user = new User(stack, 'MyUser'); | ||
|
||
// WHEN | ||
new AccessKey(stack, 'MyAccessKey', { | ||
user, | ||
status: AccessKeyStatus.INACTIVE, | ||
}); | ||
|
||
// THEN | ||
expect(stack).toHaveResourceLike('AWS::IAM::AccessKey', { | ||
Status: 'Inactive', | ||
}); | ||
}); | ||
|
||
test('access key secret ', () => { | ||
// GIVEN | ||
const app = new App(); | ||
const stack = new Stack(app, 'MyStack'); | ||
const user = new User(stack, 'MyUser'); | ||
|
||
// WHEN | ||
const accessKey = new AccessKey(stack, 'MyAccessKey', { | ||
user, | ||
}); | ||
|
||
// THEN | ||
expect(stack.resolve(accessKey.secretAccessKey)).toStrictEqual({ | ||
'Fn::GetAtt': ['MyAccessKeyF0FFBE2E', 'SecretAccessKey'], | ||
}); | ||
}); | ||
|
||
}); |
22 changes: 22 additions & 0 deletions
22
packages/@aws-cdk/aws-iam/test/integ.access-key.expected.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"Resources": { | ||
"TestUser6A619381": { | ||
"Type": "AWS::IAM::User" | ||
}, | ||
"TestAccessKey4BFC5CF5": { | ||
"Type": "AWS::IAM::AccessKey", | ||
"Properties": { | ||
"UserName": { | ||
"Ref": "TestUser6A619381" | ||
} | ||
} | ||
} | ||
}, | ||
"Outputs": { | ||
"AccessKeyId": { | ||
"Value": { | ||
"Ref": "TestAccessKey4BFC5CF5" | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { App, CfnOutput, Stack } from '@aws-cdk/core'; | ||
import { AccessKey, User } from '../lib'; | ||
|
||
const app = new App(); | ||
const stack = new Stack(app, 'integ-iam-access-key-1'); | ||
|
||
const user = new User(stack, 'TestUser'); | ||
const accessKey = new AccessKey(stack, 'TestAccessKey', { user }); | ||
|
||
new CfnOutput(stack, 'AccessKeyId', { value: accessKey.accessKeyId }); | ||
|
||
app.synth(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.