You are responsible for the cost of the AWS services used while running this workshop in your AWS account.
In this module, you will use Pulumi’s policy as code features to ensure compliant infrastructure in AWS.
We will start by creating a new directory to hold our code for this workshop and changing into it:
mkdir workshop-policy-as-code
cd workshop-policy-as-code
Within our project, we will organize our infrastructure code (our Pulumi stack) and our policy packs into separate directories. Let’s create them now:
mkdir infra policy
Let’s initialize our infrastructure stack:
cd infra
pulumi new aws-python -n workshop-policy-as-code
Accept the defaults for all prompts except possibly the AWS Region - choose a region near to you.
Replace your __main__.py
with the following content, which alters the S3 bucket to use the pulumi-read-write
ACL:
"""An AWS Python Pulumi program"""
import pulumi
import pulumi_aws as aws
# Create an AWS resource (S3 Bucket)
bucket = aws.s3.Bucket(
'my-bucket',
aws.s3.BucketArgs(
acl="public-read-write",
),
)
# Export the name of the bucket
pulumi.export('bucket_name', bucket.id)
After Pulumi has finished initializing the project, ensure you’ve activated the Python virtual environment:
source venv/bin/activate
In order to run the policy pack we are going to create, we need to add the pulumi_policy
to our dependencies, even though we will not be using it directly in our Pulumi program. (Adding pulumi_policy
is necessary due to the way Pulumi policy packs are implemented in Python.)
Run the following command to add pulumi_policy
as a dependency in the infra
directory:
echo "pulumi_policy>=1.5.0,<2.0.0" >> requirements.txt
Now we can install all of our dependencies:
pip install -r requirements.txt
Now we are ready to initialize a basic policy pack. Change to the policy
directory:
cd ../policy
Initialize a Pulumi policy pack by running the following command:
pulumi policy new aws-python
This command will create a Pulumi policy pack with a single policy that ensures S3 buckets do not have the public-read
nor the public-read-write
ACL. Feel free to check out policy/__main__.py
for the details, but we’ll explore its contents author our own rules in a future module.
Let’s activate the Python virtual environment and install requirements for the policy pack:
source venv/bin/activate
pip install -r requirements.txt
Back in the infra/
directory, let’s run the pulumi preview
command against our policy pack by specifying the --policy-pack
flag:
cd ../infra
pulumi preview --policy-pack ../policy
The command should fail. You should see output similar to the following:
Policy Violations:
[mandatory] aws-python v0.0.1 s3-no-public-read (aws:s3/bucket:Bucket: my-bucket)
Prohibits setting the publicRead or publicReadWrite permission on AWS S3 buckets.
You cannot set public-read or public-read-write on an S3 bucket. Read more about ACLs here: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html
A few things to note:
--policy-pack
flag works with both the pulumi preview
command and the pulumi up
command.--policy-pack
flag multiple times to run any number of policy packs against our Pulumi program.Each Pulumi policy in a policy pack may be set to one of the following enforcement levels:
Let’s explore how these levels work. In policy/__main__.py
, change the following line (toward the end of the file):
enforcement_level=EnforcementLevel.MANDATORY,
to this:
enforcement_level=EnforcementLevel.ADVISORY,
And let’s attempt to deploy our infrastructure:
pulumi up -y --policy-pack ../policy
You’ll see that the command succeeds and our infrastructure deploys, but we still receive a warning that our infrastructure is not in compliance:
Policy Violations:
[advisory] aws-python v0.0.1 s3-no-public-read (aws:s3/bucket:Bucket: my-bucket)
Prohibits setting the publicRead or publicReadWrite permission on AWS S3 buckets.
You cannot set public-read or public-read-write on an S3 bucket. Read more about ACLs here: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html
Now let’s disable the rule altogether. Change this:
enforcement_level=EnforcementLevel.ADVISORY,
To this:
enforcement_level=EnforcementLevel.DISABLED,
And then attempt to deploy our infrastructure:
pulumi up -y --policy-pack ../policy
The command will succeed (with no updates since we haven’t changed any of our infrastructure code - just our policy pack), but Pulumi will still indicate that our policy pack was indeed run:
Policy Packs run:
Name Version
aws-python (../policy) (local)
Let’s demonstrate how Pulumi policy packs run against resources that are already deployed. In the previous step, we were able to deploy our non-compliant infrastructure because we set our policy enforcement level to ADVISORY
. Now let’s change it back to MANDATORY
.
Change the following line in policy/__main__.py
from this:
enforcement_level=EnforcementLevel.DISABLED,
to this:
enforcement_level=EnforcementLevel.MANDATORY,
And let’s attempt to run the following command:
pulumi up -y --policy-pack ../policy
You’ll see that even though there are no changes in our infrastructure, the command still fails:
Diagnostics:
pulumi:pulumi:Stack (workshop-policy-as-code-dev):
error: preview failed
Policy Violations:
[mandatory] aws-python v0.0.1 s3-no-public-read (aws:s3/bucket:Bucket: my-bucket)
Prohibits setting the publicRead or publicReadWrite permission on AWS S3 buckets.
You cannot set public-read or public-read-write on an S3 bucket. Read more about ACLs here: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html
Pulumi policy packs are designed to check all resources in a stack, not just those that have changed. In this way, we can catch non-compliant resources that have already been deployed once a policy becomes mandatory. In a production scenario, we might consider rolling out policies first as ADVISORY
to allow teams some time to comply with the policies, then change them to MANDATORY
after teams have had sufficient time to become compliant.