Using Pulumi on AWS

In this post I shall how to use the examples provided by Pulumi to setup a static website using AWS S3.

Pre requisities

  1. These steps assume you have already cloned https://github.com/pulumi/examples.git 2. Python version >=3 3. AWS account

Setup user in IAM

  • Create a user in AWS which has access to create S3 resources
  • Export the credentials.csv
  • You will need the AWS_ACCESS_KEY_ID
  • You will need the AWS_SECRET_ACCESS_KEY
  • Note down the AWS region you want to deploy into

Deployment configuration

  • Export the following environment variables
export AWS_ACCESS_KEY_ID=<your access key id>
export AWS_SECRET_ACCESS_KEY=<your secret access key>

Initialize the stack

Make sure you are in the top level directory where you cloned the examples git repository

cd aws-py-s3-folder
pulumi stack init s3-website
pulumi config set aws:region <aws_region>

 Note

It is important to note that if you run ‘pulumi stack init s3-website’ inside a directory without a project file i.e. the** Pulumi.yaml file**.

You will get the following error message.

error: no Pulumi project found in the current working directory

Pulumi core files

  • Pulumi.yaml » main project file
  • main.py » entry point file
  • www » directory holding the static content which will be served in the S3 bucket
  • requirements.txt » a list of required Python modules

Once you have initialized the Pulumi stack you will also find an extra file called ‘Pulumi.S3-website.yaml’ which contains the AWS region you configured Pulumi to use.

You will notice the requirements.txt file containing the required Python modules.

pulumi>=2.0.0,<3.0.0
pulumi-aws>=2.0.0,<3.0.0

main.py

No HCL here except only Python for defining the deployment. As below you’ll notice the modules from pulumi are imported.

Definition of the S3 read policy, along with what files will be served.

The export of stack properties are defined at the bottom, these can later be inspected.

import json
import mimetypes
import os

from pulumi import export, FileAsset
from pulumi_aws import s3

web_bucket = s3.Bucket('s3-website-bucket', website={
    "index_document": "index.html"
})

content_dir = "www"
for file in os.listdir(content_dir):
    filepath = os.path.join(content_dir, file)
    mime_type, _ = mimetypes.guess_type(filepath)
    obj = s3.BucketObject(file,
        bucket=web_bucket.id,
        source=FileAsset(filepath),
        content_type=mime_type)

def public_read_policy_for_bucket(bucket_name):
    return json.dumps({
        "Version": "2012-10-17",
        "Statement": [{
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                f"arn:aws:s3:::{bucket_name}/*",
            ]
        }]
    })

bucket_name = web_bucket.id
bucket_policy = s3.BucketPolicy("bucket-policy",
    bucket=bucket_name,
    policy=bucket_name.apply(public_read_policy_for_bucket))

# Export the name of the bucket
export('bucket_name',  web_bucket.id)
export('website_url', web_bucket.website_endpoint)

Deployment

Python virtual env

This virtual environment is required to install dependency packages necessary for the deployment.

python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Deploy

pulumi up
Previewing update (s3-website):
        Type                    Name                         Plan       
    +   pulumi:pulumi:Stack     aws-py-s3-folder-s3-website  create     
    +   ├─ aws:s3:Bucket        s3-website-bucket            create     
    +   ├─ aws:s3:BucketPolicy  bucket-policy                create     
    +   ├─ aws:s3:BucketObject  index.html                   create     
    +   ├─ aws:s3:BucketObject  favicon.png                  create     
    +   └─ aws:s3:BucketObject  python.png                   create     
    
Resources:
    + 6 to create

Do you want to perform this update?  [Use arrows to move, enter to select, type to filter]
    yes
> no
    details
Do you want to perform this update?  [Use arrows to move, enter to select, type to filter]
> yes
    no
    details
Do you want to perform this update? yes
Updating (s3-website):
        Type                    Name                         Status      
    +   pulumi:pulumi:Stack     aws-py-s3-folder-s3-website  created     
    +   ├─ aws:s3:Bucket        s3-website-bucket            created     
    +   ├─ aws:s3:BucketObject  index.html                   created     
    +   ├─ aws:s3:BucketObject  python.png                   created     
    +   ├─ aws:s3:BucketObject  favicon.png                  created     
    +   └─ aws:s3:BucketPolicy  bucket-policy                created     
    
Outputs:
    bucket_name: "s3-website-bucket-#####"
    website_url: "s3-website-bucket-#####".s3-website-#####".amazonaws.com"                                                                                                                                          

Resources:
    + 6 created

Duration: 12s

Permalink: https://app.pulumi.com/####/aws-py-s3-folder/S3-website/updates/1

Inspect stack output

pulumi stack output
Current stack outputs (2):
    OUTPUT       VALUE
    bucket_name  s3-website-bucket-####
    website_url  s3-website-bucket-####.amazonaws.com

Open the website_url in your browser, and you will see the static contents served in S3.

Cleanup

pulumi destroy -y
Previewing destroy (s3-website):
        Type                    Name                         Plan       
    -   pulumi:pulumi:Stack     aws-py-s3-folder-s3-website  delete     
    -   ├─ aws:s3:BucketPolicy  bucket-policy                delete     
    -   ├─ aws:s3:BucketObject  python.png                   delete     
    -   ├─ aws:s3:BucketObject  favicon.png                  delete     
    -   ├─ aws:s3:BucketObject  index.html                   delete     
    -   └─ aws:s3:Bucket        s3-website-bucket            delete     
    
Outputs:
    - bucket_name: "s3-website-bucket-#####""
    - website_url: "s3-website-bucket-#####".s3-website-#####".amazonaws.com"                                                                                                                                          

Resources:
    - 6 to delete

Destroying (s3-website):
        Type                    Name                         Status      
    -   pulumi:pulumi:Stack     aws-py-s3-folder-s3-website  deleted     
    -   ├─ aws:s3:BucketPolicy  bucket-policy                deleted     
    -   ├─ aws:s3:BucketObject  index.html                   deleted     
    -   ├─ aws:s3:BucketObject  python.png                   deleted     
    -   ├─ aws:s3:BucketObject  favicon.png                  deleted     
    -   └─ aws:s3:Bucket        s3-website-bucket            deleted     
    
Outputs:
    - bucket_name: "s3-website-bucket-#####"
    - website_url: "s3-website-bucket-#####".s3-website-#####".amazonaws.com"                                                                                                                                          

Resources:
    - 6 deleted

Duration: 8s
    

Delete the stack

pulumi stack rm s3-website -y
Stack 's3-website' has been removed!

Also remove the IAM user you created for this demo.

Timing

Overall time: <1min to setup a basic S3 bucket and serve static content in AWS.

Last updated on 24 Apr 2020
Published on 24 Apr 2020