Skip to content

Commit

Permalink
Add aws-py-assume-role (converted the example aws-ts-assume-role in T… (
Browse files Browse the repository at this point in the history
pulumi#724)

* Add aws-py-assume-role (converted the example aws-ts-assume-role in TypeScript to Python)

* Ensuring the correct version of Python virtualenv is installed

* Fix aws-py-assume-role README.md, add test to examples_test.go, add aws-py-assume-role to examples/README.md

* Add aws-py-assume-role (converted the example aws-ts-assume-role in TypeScript to Python)

* Fix aws-py-assume-role README.md, add test to examples_test.go, add aws-py-assume-role to examples/README.md

* Fix minor issues (README.md spacing, add grpcio != 1.30.0)

* Update requirements.txt

Co-authored-by: stack72 <[email protected]>
  • Loading branch information
albert-zhong and stack72 committed Jun 24, 2020
1 parent 61b189f commit 84c72b0
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Example | Description |
Example | Description |
--------- | --------- |
[AppSync](aws-py-appsync) | Deploy a basic GraphQL endpoint in AWS AppSync.
[AssumeRole](aws-py-assume-role) | Use AssumeRole to create resources.
[Fargate](aws-py-fargate) | Provision a full ECS Fargate cluster running a load-balanced nginx web server.
[Resources](aws-py-resources) | Create various resources, including `cloudwatch.Dashboard`, `cloudwatch.EventRule`, `cloudwatch.LogGroup`, and `sqs.Queue`.
[S3 Folder](aws-py-s3-folder) | Serve a static website on S3.
Expand Down
88 changes: 88 additions & 0 deletions aws-py-assume-role/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# AWS Resources Using AssumeRole

This example shows how to use the AssumeRole functionality of the AWS provider
to create resources in the security context of an IAM Role assumed by the IAM
User running the Pulumi programs.

## Deploying the Example

### Prerequisites

1. [Install Pulumi](https://www.pulumi.com/docs/get-started/install/)
2. [Configure Pulumi for AWS](https://www.pulumi.com/docs/intro/cloud-providers/aws/setup/)
3. [Configure Pulumi for Python](https://www.pulumi.com/docs/intro/languages/python/)


### Part 1: Privileged Components

The Pulumi program in `create-role` requires credentials with permissions to create an IAM User, an IAM Role, and assign
an AWS Access Key to the user. The program creates a new, unprivileged user with no policies attached, and a role which
specifies a trust policy allowing assumption by the unprivileged user. The role allows the `s3:*` actions on all
resources.

You'll need to set the `create-role:unprivilegedUsername` configuration variable to the name of the unprivilged user, as
well as the AWS region in which to operate.

First, you need install dependencies. In this example we will install them in
a virtual environment named `venv`.

```bash
$ cd create-role
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install -r requirements.txt
```

Now create a new stack:

```bash
$ pulumi stack init assume-role-create
$ pulumi config set create-role:unprivilegedUsername [email protected]
$ pulumi config set aws:region us-east-1
$ pulumi up
```

The program can then be run with `pulumi up`. The outputs of the program tell you the ARN of the Role, and the Access
Key ID and Secret associated with the User:

```
$ pulumi stack output --json
{
"accessKeyId": "AKIAYJ7EUPHL3DSDH4CX",
"roleArn": "arn:aws:iam::571173272023:role/allow-s3-management-fcc71c0",
"secretAccessKey": <redacted>
}
```

### Part 2: Assuming the Role

The Pulumi program in `assume-role` creates an S3 bucket after assuming the Role created in Part 1. It should be run
with the unprivileged user credentials created in Part 1. This can be configured as follows, from the `assume-role`
directory, replacing `assume-role-create` with the name of your stack from Part 1.

```bash
$ cd assume-role
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install -r requirements.txt
$ export AWS_ACCESS_KEY_ID="$(pulumi stack output --stack assume-role-create accessKeyId)"
$ export AWS_SECRET_ACCESS_KEY="$(pulumi stack output --stack assume-role-create secretAccessKey)"
```

The configuration variable `roleToAssumeARN` must be set to the ARN of the role allowing S3 access, and the AWS region
must be set to the region in which you wish to operate:

```bash
$ pulumi stack init assume-role-assume
$ pulumi config set roleToAssumeARN "$(pulumi stack output --stack assume-role-create roleArn)"
$ pulumi config set aws:region us-east-1
```

The program can then be run with `pulumi up`. You can verify that the role is indeed assumed by looking at the
CloudTrail logs of the bucket creation operation, or by commenting out the `assumeRole` configuration in the provider
and ensuring creation is not successful.

### Clean up

To clean up your resources, run `pulumi destroy` and respond yes to the
confirmation prompt.
2 changes: 2 additions & 0 deletions aws-py-assume-role/assume-role/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.pyc
venv/
3 changes: 3 additions & 0 deletions aws-py-assume-role/assume-role/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: assume-role
runtime: python
description: Demonstrate use of AWS AssumeRole Functionality
38 changes: 38 additions & 0 deletions aws-py-assume-role/assume-role/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2016-2020, Pulumi Corporation. All rights reserved.

import pulumi_aws as aws
from pulumi_aws.config.vars import region
from pulumi import Config, ResourceOptions, export


def require_region():
"""
require_region fetches the AWS region, requiring that it exists. if it does
not exist, an exception is raised.
"""
if not region:
raise Exception('No AWS region has been configured')
return region


config = Config()
role_to_assume_arn = config.require('roleToAssumeARN')

provider = aws.Provider(
'privileged',
assume_role={
'role_arn': role_to_assume_arn,
'session_name': 'PulumiSession',
'externalId': 'PulumiApplication',
},
region=require_region()
)

# Creates an AWS resource (S3 Bucket)
bucket = aws.s3.Bucket(
'my-bucket',
opts=ResourceOptions(provider=provider)
)

# Exports the DNS name of the bucket
export('bucket_name', bucket.bucket_domain_name)
3 changes: 3 additions & 0 deletions aws-py-assume-role/assume-role/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
grpcio>=1.9.1,!=1.30.0
pulumi>=2.0.0,<3.0.0
pulumi-aws>=2.0.0,<3.0.0
3 changes: 3 additions & 0 deletions aws-py-assume-role/create-role/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: create-role
runtime: python
description: Demonstrate use of AWS AssumeRole Functionality
62 changes: 62 additions & 0 deletions aws-py-assume-role/create-role/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright 2016-2020, Pulumi Corporation. All rights reserved.

import pulumi_aws as aws
from pulumi import Config, ResourceOptions, export


def assume_role_policy_for_principal(principal):
"""
assume_role_policy_for_principal returns a well-formed policy document
which can be used to control which principals may assume an IAM Role, by
granting the `sts:AssumeRole` action to those principals.
"""
return {
'Version': '2012-10-17',
'Statement': [
{
'Sid': 'AllowAssumeRole',
'Effect': 'Allow',
'Principal': principal,
'Action': 'sts:AssumeRole'
}
]
}


config = Config()
unprivileged_username = config.require('unprivilegedUsername')

unprivileged_user = aws.iam.User(
'unprivileged-user',
name=unprivileged_username
)

unprivileged_user_creds = aws.iam.AccessKey(
'unprivileged-user-key',
user=unprivileged_user.name
)

allow_s3_management_role = aws.iam.Role('allow-s3-management',
description='Allow management of S3 buckets',
assume_role_policy=unprivileged_user.arn.apply(lambda arn:
assume_role_policy_for_principal({'AWS': arn})
)
)

policy = aws.iam.RolePolicy('allow-s3-management-policy',
role=allow_s3_management_role,
policy={
'Version': '2012-10-17',
'Statement': [{
'Sid': 'AllowS3Management',
'Effect': 'Allow',
'Resource': '*',
'Action': 's3:*',
}],
},
opts=ResourceOptions(parent=allow_s3_management_role)
)

export('roleArn', allow_s3_management_role.arn)
export('accessKeyId', unprivileged_user_creds.id)
export('secretAccessKey', unprivileged_user_creds.secret)
3 changes: 3 additions & 0 deletions aws-py-assume-role/create-role/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
grpcio>=1.9.1,!=1.30.0
pulumi>=2.0.0,<3.0.0
pulumi-aws>=2.0.0,<3.0.0
12 changes: 12 additions & 0 deletions misc/test/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,18 @@ func TestAccAwsTsAssumeRole(t *testing.T) {
integration.ProgramTest(t, &test)
}

func TestAccAwsPyAssumeRole(t *testing.T) {
test := getAWSBase(t).
With(integration.ProgramTestOptions{
Dir: path.Join(getCwd(t), "..", "..", "aws-py-assume-role", "create-role"),
Config: map[string]string{
"create-role:unprivilegedUsername": "unpriv-py",
},
})

integration.ProgramTest(t, &test)
}

func TestAccAwsTsContainers(t *testing.T) {
test := getAWSBase(t).
With(integration.ProgramTestOptions{
Expand Down

0 comments on commit 84c72b0

Please sign in to comment.