-
Notifications
You must be signed in to change notification settings - Fork 4k
/
Copy pathprecreated-role.ts
147 lines (130 loc) · 4.88 KB
/
precreated-role.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { Construct, Dependable, DependencyGroup } from 'constructs';
import { Resource, Stack } from '../../../core';
import { PolicySynthesizer } from '../../../core/lib/helpers-internal';
import { addConstructMetadata, MethodMetadata } from '../../../core/lib/metadata-resource';
import { Grant } from '../grant';
import { IManagedPolicy } from '../managed-policy';
import { Policy } from '../policy';
import { PolicyDocument } from '../policy-document';
import { PolicyStatement } from '../policy-statement';
import { AddToPrincipalPolicyResult, IPrincipal, PrincipalPolicyFragment } from '../principals';
import { IRole } from '../role';
/**
* Options for a precreated role
*/
export interface PrecreatedRoleProps {
/**
* The base role to use for the precreated role. In most cases this will be
* the `Role` or `IRole` that is being created by a construct. For example,
* users (or constructs) will create an IAM role with `new Role(this, 'MyRole', {...})`.
* That `Role` will be used as the base role for the `PrecreatedRole` meaning it be able
* to access any methods and properties on the base role.
*/
readonly role: IRole;
/**
* The assume role (trust) policy for the precreated role.
*
* @default - no assume role policy
*/
readonly assumeRolePolicy?: PolicyDocument;
/**
* If the role is missing from the precreatedRole context
*
* @default false
*/
readonly missing?: boolean;
/**
* The construct path to display in the report.
* This should be the path that the user can trace to the
* role being created in their application
*
* @default the construct path of this construct
*/
readonly rolePath?: string;
}
/**
* An IAM role that has been created outside of CDK and can be
* used in place of a role that CDK _is_ creating.
*
* When any policy is attached to a precreated role the policy will be
* synthesized into a separate report and will _not_ be synthesized in
* the CloudFormation template.
*/
export class PrecreatedRole extends Resource implements IRole {
public readonly assumeRoleAction: string;
public readonly policyFragment: PrincipalPolicyFragment;
public readonly grantPrincipal = this;
public readonly principalAccount?: string;
public readonly roleArn: string;
public readonly roleName: string;
public readonly stack: Stack;
private readonly policySynthesizer: PolicySynthesizer;
private readonly policyStatements: string[] = [];
private readonly managedPolicies: IManagedPolicy[] = [];
private readonly role: IRole;
constructor(scope: Construct, id: string, props: PrecreatedRoleProps) {
super(scope, id, {
account: props.role.env.account,
region: props.role.env.region,
});
// Enhanced CDK Analytics Telemetry
addConstructMetadata(this, props);
this.role = props.role;
this.assumeRoleAction = this.role.assumeRoleAction;
this.policyFragment = this.role.policyFragment;
this.principalAccount = this.role.principalAccount;
this.roleArn = this.role.roleArn;
this.roleName = this.role.roleName;
this.stack = this.role.stack;
const rolePath = props.rolePath ?? this.node.path;
Dependable.implement(this, {
dependencyRoots: [this.role],
});
// add a single PolicySynthesizer under the `App` scope
this.policySynthesizer = PolicySynthesizer.getOrCreate(this);
this.policySynthesizer.addRole(rolePath, {
roleName: this.roleName,
managedPolicies: this.managedPolicies,
policyStatements: this.policyStatements,
assumeRolePolicy: Stack.of(this).resolve(props.assumeRolePolicy?.toJSON()?.Statement),
missing: props.missing,
});
}
@MethodMetadata()
public attachInlinePolicy(policy: Policy): void {
const statements = policy.document.toJSON()?.Statement;
if (statements && Array.isArray(statements)) {
statements.forEach(statement => {
this.policyStatements.push(statement);
});
}
}
@MethodMetadata()
public addManagedPolicy(policy: IManagedPolicy): void {
this.managedPolicies.push(policy);
}
@MethodMetadata()
public addToPolicy(statement: PolicyStatement): boolean {
this.policyStatements.push(statement.toStatementJson());
return false;
}
@MethodMetadata()
public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult {
this.addToPolicy(statement);
// If we return `false`, the grants will try to add the statement to the resource
// (if possible).
return { statementAdded: true, policyDependable: new DependencyGroup() };
}
@MethodMetadata()
public grant(grantee: IPrincipal, ...actions: string[]): Grant {
return this.role.grant(grantee, ...actions);
}
@MethodMetadata()
public grantPassRole(grantee: IPrincipal): Grant {
return this.role.grantPassRole(grantee);
}
@MethodMetadata()
public grantAssumeRole(identity: IPrincipal): Grant {
return this.role.grantAssumeRole(identity);
}
}