Skip to content

Commit 08a2f36

Browse files
authored
feat(cloud9): support setting environment owner (#23878)
Closes #22474 ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Construct Runtime Dependencies: * [x] This PR adds new construct runtime dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-construct-runtime-dependencies) ### New Features 1. Setting environment owner . 2. The 'owner' now could be an IAMuser or Account root user(It allows AWS to determine who has permissions to manage the environment, either an IAM user or the account root user) * [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [ ] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? * [x] Unit test for ownerarn *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent ece46db commit 08a2f36

File tree

4 files changed

+126
-12
lines changed

4 files changed

+126
-12
lines changed

packages/@aws-cdk/aws-cloud9/README.md

+45-9
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@
2323

2424
This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.
2525

26-
AWS Cloud9 is a cloud-based integrated development environment (IDE) that lets you write, run, and debug your code with just a
27-
browser. It includes a code editor, debugger, and terminal. Cloud9 comes prepackaged with essential tools for popular
28-
programming languages, including JavaScript, Python, PHP, and more, so you don’t need to install files or configure your
29-
development machine to start new projects. Since your Cloud9 IDE is cloud-based, you can work on your projects from your
30-
office, home, or anywhere using an internet-connected machine. Cloud9 also provides a seamless experience for developing
31-
serverless applications enabling you to easily define resources, debug, and switch between local and remote execution of
32-
serverless applications. With Cloud9, you can quickly share your development environment with your team, enabling you to pair
26+
AWS Cloud9 is a cloud-based integrated development environment (IDE) that lets you write, run, and debug your code with just a
27+
browser. It includes a code editor, debugger, and terminal. Cloud9 comes prepackaged with essential tools for popular
28+
programming languages, including JavaScript, Python, PHP, and more, so you don’t need to install files or configure your
29+
development machine to start new projects. Since your Cloud9 IDE is cloud-based, you can work on your projects from your
30+
office, home, or anywhere using an internet-connected machine. Cloud9 also provides a seamless experience for developing
31+
serverless applications enabling you to easily define resources, debug, and switch between local and remote execution of
32+
serverless applications. With Cloud9, you can quickly share your development environment with your team, enabling you to pair
3333
program and track each other's inputs in real time.
3434

3535

3636
## Creating EC2 Environment
3737

38-
EC2 Environments are defined with `Ec2Environment`. To create an EC2 environment in the private subnet, specify
38+
EC2 Environments are defined with `Ec2Environment`. To create an EC2 environment in the private subnet, specify
3939
`subnetSelection` with private `subnetType`.
4040

4141

@@ -52,7 +52,7 @@ new cloud9.Ec2Environment(this, 'Cloud9Env2', {
5252
imageId: cloud9.ImageId.AMAZON_LINUX_2,
5353
});
5454

55-
// or specify in a different subnetSelection
55+
// or specify in a different subnetSelection
5656
const c9env = new cloud9.Ec2Environment(this, 'Cloud9Env3', {
5757
vpc,
5858
subnetSelection: {
@@ -104,3 +104,39 @@ new cloud9.Ec2Environment(this, 'C9Env', {
104104
imageId: cloud9.ImageId.AMAZON_LINUX_2,
105105
});
106106
```
107+
108+
## Specifying Owners
109+
110+
Every Cloud9 Environment has an **owner**. An owner has full control over the environment, and can invite additional members to the environment for collaboration purposes. For more information, see [Working with shared environments in AWS Cloud9](https://docs.aws.amazon.com/cloud9/latest/user-guide/share-environment.html)).
111+
112+
By default, the owner will be the identity that creates the Environment, which is most likely your CloudFormation Execution Role when the Environment is created using CloudFormation. Provider a value for the `owner` property to assign a different owner, either a specific IAM User or the AWS Account Root User.
113+
114+
`Owner` is a user that owns a Cloud9 environment . `Owner` has their own access permissions, resources. And we can specify an `Owner`in an Ec2 environment which could be of two types, 1. AccountRoot and 2. Iam User. It allows AWS to determine who has permissions to manage the environment, either an IAM user or the account root user (but using the account root user is not recommended, see [environment sharing best practices](https://docs.aws.amazon.com/cloud9/latest/user-guide/share-environment.html#share-environment-best-practices)).
115+
116+
To specify the AWS Account Root User as the environment owner, use `Owner.accountRoot()`
117+
118+
```ts
119+
declare const vpc: ec2.Vpc;
120+
new cloud9.Ec2Environment(this, 'C9Env', {
121+
vpc,
122+
imageId: cloud9.ImageId.AMAZON_LINUX_2,
123+
124+
owner: cloud9.Owner.accountRoot('111111111')
125+
})
126+
```
127+
128+
To specify a specific IAM User as the environment owner, use `Owner.user()`. The user should have the `AWSCloud9Administrator` managed policy
129+
130+
```ts
131+
import * as iam from '@aws-cdk/aws-iam';
132+
133+
const user = new iam.User(this, 'user');
134+
user.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSCloud9Administrator'));
135+
declare const vpc: ec2.Vpc;
136+
new cloud9.Ec2Environment(this, 'C9Env', {
137+
vpc,
138+
imageId: cloud9.ImageId.AMAZON_LINUX_2,
139+
140+
owner: cloud9.Owner.user(user)
141+
})
142+
```

packages/@aws-cdk/aws-cloud9/lib/environment.ts

+46-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as codecommit from '@aws-cdk/aws-codecommit';
22
import * as ec2 from '@aws-cdk/aws-ec2';
3+
import { IUser } from '@aws-cdk/aws-iam';
34
import * as cdk from '@aws-cdk/core';
45
import { Construct } from 'constructs';
56
import { CfnEnvironmentEC2 } from '../lib/cloud9.generated';
@@ -53,11 +54,19 @@ export enum ImageId {
5354
*/
5455
UBUNTU_18_04 = 'ubuntu-18.04-x86_64'
5556
}
56-
5757
/**
5858
* Properties for Ec2Environment
5959
*/
6060
export interface Ec2EnvironmentProps {
61+
/**
62+
* Owner of the environment.
63+
*
64+
* The owner has full control of the environment and can invite additional members.
65+
*
66+
* @default - The identity that CloudFormation executes under will be the owner
67+
*/
68+
readonly owner?: Owner;
69+
6170
/**
6271
* The type of instance to connect to the environment.
6372
*
@@ -182,6 +191,7 @@ export class Ec2Environment extends cdk.Resource implements IEc2Environment {
182191
const c9env = new CfnEnvironmentEC2(this, 'Resource', {
183192
name: props.ec2EnvironmentName,
184193
description: props.description,
194+
ownerArn: props.owner?.ownerArn,
185195
instanceType: props.instanceType?.toString() ?? ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.MICRO).toString(),
186196
subnetId: this.vpc.selectSubnets(vpcSubnets).subnetIds[0],
187197
repositories: props.clonedRepositories ? props.clonedRepositories.map(r => ({
@@ -217,3 +227,38 @@ export class CloneRepository {
217227

218228
private constructor(public readonly repositoryUrl: string, public readonly pathComponent: string) {}
219229
}
230+
231+
/**
232+
* An environment owner
233+
*
234+
*
235+
*/
236+
export class Owner {
237+
/**
238+
* Make an IAM user the environment owner
239+
*
240+
* User need to have AWSCloud9Administrator permissions
241+
* @see https://docs.aws.amazon.com/cloud9/latest/user-guide/share-environment.html#share-environment-about
242+
*
243+
* @param user the User object to use as the environment owner
244+
*/
245+
public static user(user: IUser): Owner {
246+
return { ownerArn: user.userArn };
247+
}
248+
249+
250+
/**
251+
* Make the Account Root User the environment owner (not recommended)
252+
*
253+
* @param accountId the AccountId to use as the environment owner.
254+
*/
255+
public static accountRoot(accountId: string): Owner {
256+
return { ownerArn: `arn:aws:iam::${accountId}:root` };
257+
}
258+
259+
/**
260+
*
261+
* @param ownerArn of environment owner.
262+
*/
263+
private constructor(public readonly ownerArn: string) {}
264+
}

packages/@aws-cdk/aws-cloud9/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,15 @@
9292
"dependencies": {
9393
"@aws-cdk/aws-codecommit": "0.0.0",
9494
"@aws-cdk/aws-ec2": "0.0.0",
95+
"@aws-cdk/aws-iam": "0.0.0",
9596
"@aws-cdk/core": "0.0.0",
9697
"constructs": "^10.0.0"
9798
},
9899
"homepage": "https://github.com/aws/aws-cdk",
99100
"peerDependencies": {
100101
"@aws-cdk/aws-codecommit": "0.0.0",
101102
"@aws-cdk/aws-ec2": "0.0.0",
103+
"@aws-cdk/aws-iam": "0.0.0",
102104
"@aws-cdk/core": "0.0.0",
103105
"constructs": "^10.0.0"
104106
},

packages/@aws-cdk/aws-cloud9/test/cloud9.environment.test.ts

+33-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Match, Template } from '@aws-cdk/assertions';
22
import * as codecommit from '@aws-cdk/aws-codecommit';
33
import * as ec2 from '@aws-cdk/aws-ec2';
4+
import * as iam from '@aws-cdk/aws-iam';
45
import * as cdk from '@aws-cdk/core';
56
import * as cloud9 from '../lib';
6-
import { ConnectionType, ImageId } from '../lib';
7+
import { ConnectionType, ImageId, Owner } from '../lib';
78

89
let stack: cdk.Stack;
910
let vpc: ec2.IVpc;
@@ -79,7 +80,6 @@ test('throw error when subnetSelection not specified and the provided VPC has no
7980
test('can use CodeCommit repositories', () => {
8081
// WHEN
8182
const repo = codecommit.Repository.fromRepositoryName(stack, 'Repo', 'foo');
82-
8383
new cloud9.Ec2Environment(stack, 'C9Env', {
8484
vpc,
8585
clonedRepositories: [
@@ -114,6 +114,37 @@ test('can use CodeCommit repositories', () => {
114114
});
115115
});
116116

117+
test('environment owner can be an IAM user', () => {
118+
// WHEN
119+
const user = new iam.User(stack, 'User', {
120+
userName: 'testUser',
121+
});
122+
new cloud9.Ec2Environment(stack, 'C9Env', {
123+
vpc,
124+
imageId: cloud9.ImageId.AMAZON_LINUX_2,
125+
owner: Owner.user(user),
126+
});
127+
// THEN
128+
Template.fromStack(stack).hasResourceProperties('AWS::Cloud9::EnvironmentEC2', {
129+
OwnerArn: {
130+
'Fn::GetAtt': ['User00B015A1', 'Arn'],
131+
},
132+
});
133+
});
134+
135+
test('environment owner can be account root', () => {
136+
// WHEN
137+
new cloud9.Ec2Environment(stack, 'C9Env', {
138+
vpc,
139+
imageId: cloud9.ImageId.AMAZON_LINUX_2,
140+
owner: Owner.accountRoot('12345678'),
141+
});
142+
// THEN
143+
Template.fromStack(stack).hasResourceProperties('AWS::Cloud9::EnvironmentEC2', {
144+
OwnerArn: 'arn:aws:iam::12345678:root',
145+
});
146+
});
147+
117148
test.each([
118149
[ConnectionType.CONNECT_SSH, 'CONNECT_SSH'],
119150
[ConnectionType.CONNECT_SSM, 'CONNECT_SSM'],

0 commit comments

Comments
 (0)