<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: John McCracken</title>
    <description>The latest articles on Forem by John McCracken (@johnmccuk).</description>
    <link>https://forem.com/johnmccuk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F110549%2F67ea409c-5a0f-40ca-9cdd-994e3958238e.jpg</url>
      <title>Forem: John McCracken</title>
      <link>https://forem.com/johnmccuk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/johnmccuk"/>
    <language>en</language>
    <item>
      <title>AWS IAM Roles Anywhere Demo</title>
      <dc:creator>John McCracken</dc:creator>
      <pubDate>Sun, 24 Aug 2025 19:00:20 +0000</pubDate>
      <link>https://forem.com/johnmccuk/aws-iam-roles-anywhere-demo-3gl4</link>
      <guid>https://forem.com/johnmccuk/aws-iam-roles-anywhere-demo-3gl4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;IAM user access keys are the normal way to access AWS from an external source. Generally this is the method to use for machine/code access to your AWS estate. &lt;/p&gt;

&lt;p&gt;This is ok, but come with some issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long lived credentials expand the window of opportunity for an attacker to exploit the access key.&lt;/li&gt;
&lt;li&gt;Rotating secrets can be hard to manage; synchronising credentials rotating with third parties can be complex.&lt;/li&gt;
&lt;li&gt;It just doesn't scale, anything over a handful of access keys becomes hard to manage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AWS preferred solution is to use &lt;a href="https://aws.amazon.com/iam/roles-anywhere/" rel="noopener noreferrer"&gt;AWS IAM Roles Anywhere&lt;/a&gt; for workloads outside of AWS.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Short term rotating credentials&lt;/li&gt;
&lt;li&gt;Uses industry standard X.509 certificates&lt;/li&gt;
&lt;li&gt;Reduces management complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although a bit more complex to set up, AWS IAM Roles Anywhere is a much more elegant, scalable solution for workloads. It also ticks all current AWS security best practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does IAM Roles Anywhere work?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6m3rklocglev65fks26.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6m3rklocglev65fks26.jpg" alt="IAM Roles Anywhere process flow" width="661" height="678"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Workloads use &lt;strong&gt;SSL Certificates&lt;/strong&gt; (&lt;strong&gt;end-entity certificate&lt;/strong&gt;) which have been signed by a &lt;strong&gt;Certificate Authority&lt;/strong&gt; (&lt;strong&gt;CA&lt;/strong&gt;). The CA can either be external or provided by AWS.&lt;/li&gt;
&lt;li&gt;Create a Trust Anchor between IAM Roles Anywhere and the CA&lt;/li&gt;
&lt;li&gt;Create a Profile, which defines the IAM policy to apply after successful authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be aware that although IAM Roles Anywhere is free, if you use AWS Private CA there will be a cost, it’s around $400 per month! I believe you can cancel within the first 30 days free of charge.&lt;/p&gt;

&lt;p&gt;In this demo, I’ll stick with a free external self generated one. Its a bit of a pain to generate, but hopefully this demo makes it as painless as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this guide intends to do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Generate an external CA&lt;/li&gt;
&lt;li&gt;Generate an end-entity certificate which is signed off against the CA.&lt;/li&gt;
&lt;li&gt;Setup a IAM Roles Anywhere Trust Anchor with the CA certificate&lt;/li&gt;
&lt;li&gt;Setup a IAM Roles Anywhere Profile and link a IAM Policy&lt;/li&gt;
&lt;li&gt;Setup a local machine to use &lt;strong&gt;aws_signing_helper&lt;/strong&gt; in an AWS Profile.&lt;/li&gt;
&lt;li&gt;Demonstrate it works with AWS CLI and Python/boto3.
##Setting up IAM Roles Anywhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve tried to script as much as possible, that way you can get it running as quickly as possible and it still offers the full details for those who want to dig deeper under the hood.&lt;/p&gt;

&lt;p&gt;I’ve created a repo for all this goodness: &lt;a href="https://github.com/johnmccuk/aws-iam-roles-anywhere-public-demo" rel="noopener noreferrer"&gt;aws-iam-roles-anywhere-public-demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This contains the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shell script to generate CA and end certificates&lt;/li&gt;
&lt;li&gt;Terraform to deploy to AWS&lt;/li&gt;
&lt;li&gt;Python example script to test access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All instructions are for Linux/MacOS. If you're using Windows, you've got bigger problems than trying to follow this blog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate a Certificate Authority and a End Entity Certificate
&lt;/h3&gt;

&lt;p&gt;On the CLI and clone the repo and go to the root directory. There is a bash script located here called &lt;code&gt;create-ca.sh&lt;/code&gt; which can be used to automatically generate the required Certificates. &lt;/p&gt;

&lt;p&gt;This uses a config file &lt;code&gt;root-ca/root-ca.conf&lt;/code&gt;, you can use the default values or edit to suit your requirements.&lt;/p&gt;

&lt;p&gt;Open the script &lt;a href="https://github.com/johnmccuk/aws-iam-roles-anywhere-public-demo/blob/main/create-ca.sh" rel="noopener noreferrer"&gt;create-ca.sh&lt;/a&gt; and have a look over what it's actually doing, the comments hopefully help clarify.&lt;/p&gt;

&lt;p&gt;The certificates values are stored in &lt;a href="https://github.com/johnmccuk/aws-iam-roles-anywhere-public-demo/blob/main/root-ca/root-ca.conf" rel="noopener noreferrer"&gt;root-ca.conf&lt;/a&gt; and &lt;a href="https://github.com/johnmccuk/aws-iam-roles-anywhere-public-demo/blob/main/root-ca/client-ca.conf" rel="noopener noreferrer"&gt;client-ca.conf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you're comfortable with the contents, run the script: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;sh ./create-ca.sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When prompted, select &lt;strong&gt;Y&lt;/strong&gt; for any prompts.&lt;/p&gt;

&lt;p&gt;You should now have the following created in the root-ca folder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;certs folder containing a CA .pem file&lt;/li&gt;
&lt;li&gt;db folder with CA version data&lt;/li&gt;
&lt;li&gt;private folder with a private key and certificate signing request file&lt;/li&gt;
&lt;li&gt;clients folder with end-entity certificate key/pem file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is all the files required to get started. Be aware this is all basic stuff and shouldn't be used in a production environment. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: this script copies the following files from the ./clients/ folder into your ~/.ssh folder: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;~/.ssh/iam-roles-anywhere-demo.key&lt;/code&gt;&lt;br&gt;
&lt;code&gt;~/.ssh/iam-roles-anywhere-demo.crt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Please delete these manually afterwards.&lt;/p&gt;
&lt;h3&gt;
  
  
  Deploy the Infrastructure as Code
&lt;/h3&gt;

&lt;p&gt;Feel free to deploy by click-ops, it's pretty self explanatory, but everything really should be IaC.&lt;/p&gt;

&lt;p&gt;Make sure you have authenticated to the AWS account you wish to use, by pasting Access keys into the CLI or however you normally do it.&lt;/p&gt;

&lt;p&gt;From the root directory, &lt;code&gt;cd terraform&lt;/code&gt;then&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform init&lt;/code&gt;&lt;br&gt;
&lt;code&gt;terraform apply&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Plan output should create the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;aws_rolesanywhere_trust_anchor&lt;/strong&gt;&lt;br&gt;
Create a Trust Anchor, this connects IAM Roles Anywhere to the certificate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;aws_iam_role&lt;/strong&gt;&lt;br&gt;
This is the role used by IAM Anywhere, it has a condition that the certificate Common Name (CN) must be ‘IAM Anywhere Demo’.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;aws_iam_role_policy_attachment&lt;/strong&gt;&lt;br&gt;
Attach the managed policy &lt;strong&gt;AmazonS3ReadOnlyAccess&lt;/strong&gt; to the role&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;aws_rolesanywhere_profile&lt;/strong&gt;&lt;br&gt;
Create an IAM Roles Anywhere Profile called ‘iam-roles-anywhere-demo’. Note that the profile also is linked to the managed policy &lt;strong&gt;AmazonS3ReadOnlyAccess&lt;/strong&gt;. The profile can set the maximum permission boundary. &lt;/p&gt;

&lt;p&gt;For example, if I had attached AmazonS3FullAccess to the role, the Profile permissions would restrict S3 permissions to read only.&lt;/p&gt;

&lt;p&gt;Check over the plan and if all looks good to you, type &lt;strong&gt;yes&lt;/strong&gt; to deploy.&lt;/p&gt;

&lt;p&gt;If all goes well, the resources should be deployed to your specified AWS Account. &lt;/p&gt;

&lt;p&gt;The output should contain a key &lt;strong&gt;credential_process&lt;/strong&gt;, copy the value for this key and paste it somewhere safe for now. This outputs the aws command required later to authenticate. It should be something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;credential_process = "~/.aws/aws_signing_helper credential-process --certificate ~/.ssh/iam-roles-anywhere.crt --private-key ~/.ssh/iam-roles-anywhere.key --trust-anchor-arn arn:aws:rolesanywhere:eu-west-1:ACCOUNTID:trust-anchor/880ee543-af45-48c7-b5cd-bf0b73e95059 --profile-arn arn:aws:rolesanywhere:eu-west-1:ACCOUNTID:profile/048f1bf7-da4c-41cd-99ed-ee6b93021297 --role-arn arn:aws:iam::ACCOUNTID:role/iam-roles-anywhere-demo"
profile-arn = "arn:aws:rolesanywhere:eu-west-1:ACCOUNTID:profile/048f1bf7-da4c-41cd-99ed-ee6b93021297"
role-arn = "arn:aws:iam::ACCOUNTID:role/iam-roles-anywhere-demo"
trust-anchor-arn = "arn:aws:rolesanywhere:eu-west-1:ACCOUNTID:trust-anchor/880ee543-af45-48c7-b5cd-bf0b73e95059"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test AWS Access
&lt;/h2&gt;

&lt;p&gt;If you want to view the resources in the AWS console, go to the IAM Dashboard, then Roles and then scroll to the bottom of the main window.&lt;/p&gt;

&lt;p&gt;Firstly, AWS provide &lt;a href="https://docs.aws.amazon.com/rolesanywhere/latest/userguide/credential-helper.html" rel="noopener noreferrer"&gt;aws_signing_helper&lt;/a&gt; to simplify access, download and install, make sure its in your &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can use this file to retrieve short term credentials and then add them to environmental variables as you can with AWS IAM access keys, but I have found a better way is to update the &lt;code&gt;~/.aws/config&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;~/.aws/config&lt;/code&gt; and create a new entry profile:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[profile iam-roles-anywhere-demo]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now directly below this, paste the Terraform output mentioned previously, so it should end up something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[profile iam-roles-anywhere-demo]
credential_process = aws_signing_helper credential-process --certificate ~/.ssh/iam-roles-anywhere.crt --private-key ~/.ssh/iam-roles-anywhere.key --trust-anchor-arn arn:aws:rolesanywhere:eu-west-1:ACCOUNTID:trust-anchor/880ee543-af45-48c7-b5cd-bf0b73e95059 --profile-arn arn:aws:rolesanywhere:eu-west-1:ACCOUNTID:profile/048f1bf7-da4c-41cd-99ed-ee6b93021297 --role-arn arn:aws:iam::ACCOUNTID:role/iam-roles-anywhere-demo
profile-arn = "arn:aws:rolesanywhere:eu-west-1:ACCOUNTID:profile/048f1bf7-da4c-41cd-99ed-ee6b93021297"
role-arn = "arn:aws:iam::ACCOUNTID:role/iam-roles-anywhere-demo"
trust-anchor-arn = "arn:aws:rolesanywhere:eu-west-1:ACCOUNTID:trust-anchor/880ee543-af45-48c7-b5cd-bf0b73e95059”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now save and exit file&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: You might need to replace &lt;code&gt;/.ssh&lt;/code&gt; with the full path, in my case this was &lt;code&gt;/Users/john.mccracken/.ssh&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing with AWS CLI
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;aws sts get-caller-identity --profile iam-roles-anywhere-demo&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "UserId": "XXXX",
    "Account": "1234567890",
    "Arn": "arn:aws:sts::1234567890:assumed-role/iam-roles-anywhere-demo/00bc75fc5a6709cca9402a061453a2f3a9"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then try&lt;/p&gt;

&lt;p&gt;&lt;code&gt;aws s3 ls --profile iam-roles-anywhere-demo&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing programmatically with Python/boto3
&lt;/h3&gt;

&lt;p&gt;In the python-iam-anywhere-test folder, there is a test.py file which will list buckets from the Account, there is a poetry.lock file with the required dependencies (boto3).&lt;/p&gt;

&lt;p&gt;From the root directory, cd &lt;code&gt;python-iam-anywhere-test&lt;/code&gt; then&lt;/p&gt;

&lt;p&gt;&lt;code&gt;poetry install&lt;/code&gt;&lt;br&gt;
&lt;code&gt;poetry run python test.py&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This should list all S3 buckets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;IAM Roles Anywhere is a great elegant solution for external access to AWS resources. Setting up your own CA is a pain, but it's once done, the integration with AWS is pretty seamless and straightforward. &lt;/p&gt;

&lt;p&gt;aws_signing_helper makes life really simple, if you want an idea of how complex the process is under the hood, check out the &lt;a href="https://github.com/aws/rolesanywhere-credential-helper" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now I have IAM Roles Anywhere setup, I intend to use it going forward rather than access keys.&lt;/p&gt;

&lt;p&gt;Any feedback, please get in touch. I'd love to hear from you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional links
&lt;/h2&gt;

&lt;p&gt;Always standing on the shoulder of giants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/cyberark-engineering/calling-aws-services-from-your-on-premises-servers-using-iam-roles-anywhere-3e335ed648be" rel="noopener noreferrer"&gt;Create a CA for use with AWS IAM Roles Anywhere&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/blogs/security/iam-roles-anywhere-with-an-external-certificate-authority/" rel="noopener noreferrer"&gt;IAM Roles Anywhere with an external certificate authority&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/blogs/security/extend-aws-iam-roles-to-workloads-outside-of-aws-with-iam-roles-anywhere/" rel="noopener noreferrer"&gt;Extend AWS IAM roles to workloads outside of AWS with IAM Roles Anywhere&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/rolesanywhere/latest/userguide/credential-helper.html#credential-helper-credential-process" rel="noopener noreferrer"&gt;Get temporary security credentials from IAM Roles Anywhere&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ivanr/bulletproof-tls/tree/master/private-ca" rel="noopener noreferrer"&gt;Examples derived from Ivans Ristic's Github&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>1Password CLI, AWS and Terraform</title>
      <dc:creator>John McCracken</dc:creator>
      <pubDate>Thu, 02 Feb 2023 10:39:46 +0000</pubDate>
      <link>https://forem.com/johnmccuk/1password-cli-aws-and-terraform-5g30</link>
      <guid>https://forem.com/johnmccuk/1password-cli-aws-and-terraform-5g30</guid>
      <description>&lt;h2&gt;
  
  
  The issue
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.1password.com/docs/cli" rel="noopener noreferrer"&gt;1Password CLI&lt;/a&gt; is great, having a single source for managing access keys and being able to use fingerprint ID on a Mac is such a cool feature. The AWS plugin works great, but if you want to use AWS through a third party (in this case Terraform), I failed to get it to work.&lt;/p&gt;

&lt;p&gt;❕ &lt;em&gt;This blog post is based on finding a MacOS solution, mileage may vary on other operating systems.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The plan
&lt;/h2&gt;

&lt;p&gt;After some searching I came across this guide &lt;a href="https://kfalck.net/2018/03/18/storing-aws-cli-credentials-in-1password/" rel="noopener noreferrer"&gt;Storing AWS CLI Credentials in 1Password&lt;/a&gt; by Kenneth Falck. Its now outdated and didn't work for me, but it was more than enough to point in the right direction.&lt;/p&gt;

&lt;p&gt;So firstly, setup everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.1password.com/docs/cli/get-started#install" rel="noopener noreferrer"&gt;1Password CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.1password.com/docs/cli/shell-plugins/aws" rel="noopener noreferrer"&gt;1Password AWS plugin&lt;/a&gt;. ❕ I ignored &lt;em&gt;Step 2: Source the plugins.sh file&lt;/em&gt; here as the alias it adds is no longer required.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stedolan.github.io/jq/" rel="noopener noreferrer"&gt;jq tool&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;next, edit the &lt;code&gt;~/.aws/config&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[default]
credential_process = sh -c "op item get '*1PASSWORD OBJ*' --format json | jq '.fields | map({(.label):.}) | add | {Version:1, AccessKeyId:."access key id".value, SecretAccessKey:."secret access key".value}'"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Amend the &lt;code&gt;*1PASSWORD OBJ*&lt;/code&gt; name to the name of the 1Password access key entry.&lt;br&gt;
If you followed the guides, the fields should be &lt;code&gt;access key id&lt;/code&gt; and &lt;code&gt;secret access key&lt;/code&gt;, if different, change accordingly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html" rel="noopener noreferrer"&gt;credential_process&lt;/a&gt; allows you to load credentials from an external process.&lt;/p&gt;

&lt;p&gt;To check it works, try &lt;code&gt;aws iam get-user&lt;/code&gt;, if this works, try a terraform command. &lt;/p&gt;

&lt;p&gt;Hopefully it works... 😬&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href="https://kfalck.net/" rel="noopener noreferrer"&gt;Kenneth Falck&lt;/a&gt; for initially solving this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>1password</category>
      <category>aws</category>
      <category>terraform</category>
      <category>security</category>
    </item>
    <item>
      <title>Isolating PHP with Docker Containers</title>
      <dc:creator>John McCracken</dc:creator>
      <pubDate>Thu, 01 Nov 2018 20:30:41 +0000</pubDate>
      <link>https://forem.com/johnmccuk/isolating-php-with-docker-containers-4epn</link>
      <guid>https://forem.com/johnmccuk/isolating-php-with-docker-containers-4epn</guid>
      <description>&lt;p&gt;Docker is a great piece of technology. It's a nice way to setup a development environment or experiment with new software without actually clogging up your own system. &lt;/p&gt;

&lt;p&gt;I was messing around with serving some webpages using Docker with Apache and PHP. How could I easily switch PHP versions without clogging up my local machine or creating multiple Docker images/Vagrant boxes? I'm sure lots of developers could easily find a solution, but I must admit I do have trouble conceptualising container solutions. The layers of abstraction cause a mental block, I'm sure I'm not alone with this. &lt;/p&gt;

&lt;p&gt;It struck me that Apache/PHP doesn't fit into the Docker &lt;strong&gt;&lt;em&gt;one process per container&lt;/em&gt;&lt;/strong&gt; doctrine. PHP and Apache as so glued together that in regard to &lt;a href="https://en.wikipedia.org/wiki/Separation_of_concerns" rel="noopener noreferrer"&gt;separation of concerns&lt;/a&gt;, it's a non starter.&lt;/p&gt;

&lt;p&gt;I really wanted my web server container to be isolated from the programming language. Switching to NGINX and PHP-FPM offers a much cleaner separation, which allows us to switch language versions with ease. This could be handy if you have legacy sites that require different versions or you want to try out a site before upgrading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;So the plan will be that when a request is sent to the &lt;em&gt;test5.com/index.php&lt;/em&gt; url, the Nginx container will pass the request to process &lt;em&gt;index.php&lt;/em&gt; onto a container running PHP 5 and obviously the equivalent for &lt;em&gt;test7.com/index.php&lt;/em&gt; and PHP 7.&lt;/p&gt;

&lt;p&gt;First things first, add 2 entries to the &lt;code&gt;/etc/hosts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127.0.0.1 test5.com
127.0.0.1 test7.com 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These will be the addresses we use to access the Nginx container.&lt;/p&gt;

&lt;p&gt;Download or clone the repository from GitHub &lt;a href="https://github.com/johnmccuk/docker-php-isolation-example" rel="noopener noreferrer"&gt;docker-php-isolation-example&lt;/a&gt; to a suitable place on your system. All commands will be ran from the CLI from within this folder.&lt;/p&gt;

&lt;p&gt;The folder structure is relatively simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;webroot&lt;/strong&gt; - the self explanatory folder which contains a file called &lt;code&gt;index.php&lt;/code&gt; which contains the &lt;code&gt;phpinfo()&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;site.conf&lt;/strong&gt; - Nginx site(s) configuration file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;docker-compose.yml&lt;/strong&gt; - docker setup configuration file.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;em&gt;docker-compose.yml&lt;/em&gt; file sets up 3 containers, all based on Alpine Linux image, so the total for the containers is a tiny 120Mb.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '2'
services:
    web:
        image: nginx:alpine
        ports:
            - "8080:80"
        volumes:
            - ./webroot:/var/www/html
            - ./site.conf:/etc/nginx/conf.d/site.conf
        links:
            - php7
            - php5
    php7:
        image: php:7-fpm-alpine
        volumes:
            - ./webroot:/var/www/html
    php5:
        image: php:5-fpm-alpine
        volumes:
            - ./webroot:/var/www/html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main container is the Nginx proxy, which is the only container with an external port (8080). This container proxy's any valid requests to the two other containers, one running php 7 php-fpm, the other php 5 php-fpm on port 9000.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FphpIsolationDiagram-a7498ea5f35c8306a74a36f106161f27-0c130.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FphpIsolationDiagram-a7498ea5f35c8306a74a36f106161f27-0c130.png" alt="phpIsolationDiagram" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;the &lt;em&gt;webroot&lt;/em&gt; folder is shared between all 3 containers, Nginx needs this to serve any non PHP files, while the PHP containers need access to the PHP files.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;site.conf&lt;/em&gt; file contains defines how Nginx treats requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    listen 80;
    index index.php;
    server_name test7.com;
    root /var/www/html/;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php7:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

server {
    listen 80;
    index index.php;
    server_name test5.com;
    root /var/www/html/;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php5:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm sure theres a way to incorporate both of these addresses into one and use a regular expression, but lifes too short.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it
&lt;/h2&gt;

&lt;p&gt;From the CLI, navigate into the folder where you downloaded the repository and type &lt;code&gt;docker-compose up -d&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This will dowload the images if there not saved locally already and start the containers. Once finished type &lt;code&gt;docker ps&lt;/code&gt; to make sure the 3 containers are running.&lt;/p&gt;

&lt;p&gt;So open your browser of choice and type test5.com:8080 and you should see phpinfo() for PHP 5.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FScreen-Shot-2017-10-07-at-08.04.07-c5d55953237557557f278eafbd413f26-e7328.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FScreen-Shot-2017-10-07-at-08.04.07-c5d55953237557557f278eafbd413f26-e7328.png" alt="Screen-Shot-2017-10-07-at-08.04.07" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, type test7.com:8080 and you should see phpinfo() for, you guessed it, PHP 7!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FScreen-Shot-2017-10-07-at-08.03.49-fa6fd10b5835979f416664078d8ea1e9-29566.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FScreen-Shot-2017-10-07-at-08.03.49-fa6fd10b5835979f416664078d8ea1e9-29566.png" alt="Screen-Shot-2017-10-07-at-08.03.49" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there you go, we can define which version of PHP to use to process the same index.php file, hours of fun...&lt;/p&gt;

&lt;h2&gt;
  
  
  Tidying up
&lt;/h2&gt;

&lt;p&gt;Had enough excitement? To close down the running containers, type &lt;code&gt;docker-compose down&lt;/code&gt;, this should close and remove the containers. &lt;/p&gt;

&lt;p&gt;If you want to remove the downloaded images, type &lt;code&gt;docker images&lt;/code&gt; and then &lt;code&gt;docker rmi IMAGE ID&lt;/code&gt;, for example &lt;code&gt;docker rmi 4fe1b7f08eb1 8b057b9de580 1b95155d2daf&lt;/code&gt; would remove the 3 images with IDs &lt;em&gt;4fe1b7f08eb1&lt;/em&gt;, &lt;em&gt;8b057b9de580&lt;/em&gt; and &lt;em&gt;1b95155d2daf&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;The concept of offering PHP as a kinda ‘Software as a Service’ might be a humble idea, but its something I find really cool. Being able to isolate versions of a programming language interests me greatly and might be something that I try and incorporate in future projects.&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;Isolating PHP with Docker Containers first appeared on my &lt;a href="https://blog.john-mccracken.com" rel="noopener noreferrer"&gt;blog site&lt;/a&gt; on 07/10/2017.&lt;/sup&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>php</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Automate AWS security group with CloudFlare IPs</title>
      <dc:creator>John McCracken</dc:creator>
      <pubDate>Sun, 28 Oct 2018 20:31:56 +0000</pubDate>
      <link>https://forem.com/johnmccuk/automate-aws-security-group-with-cloudflare-ips-la6</link>
      <guid>https://forem.com/johnmccuk/automate-aws-security-group-with-cloudflare-ips-la6</guid>
      <description>&lt;p&gt;I'm a big fan of &lt;a href="https://www.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt;. Even the basic free service offers numerous caching and security features which would be pretty time consuming to implement yourself. At the very least it offers a free and very easy ssl certificate service.&lt;/p&gt;

&lt;p&gt;Security should always be thought of as a layered process and Cloudflare plays an important role as a first line of defence. The ability to block out malicious or suspicious requests before it even reaches your server is a great asset. Obviously this only works if Cloudflare is positioned in front of your server and requests are forced to go through Cloudflare's proxy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FScreen-Shot-2017-02-26-at-20.13.23-2aa87d5b778e172de89f2ed23927f4b5-6080a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FScreen-Shot-2017-02-26-at-20.13.23-2aa87d5b778e172de89f2ed23927f4b5-6080a.png" alt="Cloudlfare protection" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For any bad guy worth his salt, its relatively simple to figure out the real IP address of the server and bypass Cloudflare. Your server is now more vulnerable and security is now down to your server skills, up to date software and coding best practices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FScreen-Shot-2017-02-26-at-20.15.56-615186bc63e1d4797da793b4028a0680-e5f4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2FScreen-Shot-2017-02-26-at-20.15.56-615186bc63e1d4797da793b4028a0680-e5f4c.png" alt="Bad guys, doing their thing!" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Therefore its pretty important to stop direct access to your sites by only allowing web access from Cloudflare IP addresses. This blob post will cover doing this in the &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;Amazon Web Services&lt;/a&gt; environment: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a Security Group&lt;/li&gt;
&lt;li&gt;Assign Security Group to relevant EC2 instances.&lt;/li&gt;
&lt;li&gt;Create A Lambda function to regularly retrieve Cloudflare's IP address list and update the security group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't use AWS, the theory is still sound and wouldn't take much tweaking to achieve the same though a cron service and iptables. &lt;/p&gt;

&lt;p&gt;The Lambda code uses Python 2.7 and uses the &lt;a href="http://boto3.readthedocs.io/en/latest/reference/services/ec2.html#securitygroup" rel="noopener noreferrer"&gt;Boto3&lt;/a&gt; library to communicate with AWS.&lt;/p&gt;

&lt;p&gt;The Lambda Python code is available from the &lt;a href="https://github.com/johnmccuk/cloudflare-ip-security-group-update" rel="noopener noreferrer"&gt;github code repository&lt;/a&gt;. I'm relatively new to Python, so feel free to contribute and improve. &lt;/p&gt;

&lt;h2&gt;
  
  
  Create EC2 Security Group
&lt;/h2&gt;

&lt;p&gt;Firstly create a Security Group and take note of the Group ID. This can be done through the AWS web interface:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2Faws-security-group-2-4fb9c9b721fb138410e9b406eba8ae35-c795e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2Faws-security-group-2-4fb9c9b721fb138410e9b406eba8ae35-c795e.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or from the &lt;a href="http://docs.aws.amazon.com/cli/latest/userguide/cli-ec2-sg.html" rel="noopener noreferrer"&gt;command line&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;aws ec2 create-security-group --group-name cloudflare-access --description "http(s) access from Cloudflare IPs only" --vpc-id VPC-ID-GOES-HERE&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Keep a note of the Group ID as will use this as an environmental variable with our Lambda code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Lambda Function
&lt;/h2&gt;

&lt;p&gt;As these IP addresses may change, we need some code to update them. As were in the AWS environment, we can easily do this from a Lambda function which we can run on a regular basis for next to nothing.&lt;/p&gt;

&lt;p&gt;If your not familiar with AWS Lambda, its software as a service facility where you can place some code (C#, Java Python or Node) and you only pay for the time that the code runs. No need to maintain a server, just code, pure glorious code!&lt;/p&gt;

&lt;p&gt;So heres the code repository for one &lt;a href="https://github.com/johnmccuk/cloudflare-ip-security-group-update" rel="noopener noreferrer"&gt;I did earlier&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The required code is in the file &lt;strong&gt;cf-security-group-update.py&lt;/strong&gt;. For those not familiar &lt;code&gt;def lambda_handler(event, context):&lt;/code&gt; is the main function thats called when the Lambda is triggered. What happens from here should be self explanatory from the descriptive function names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Select blueprint
&lt;/h3&gt;

&lt;p&gt;From the AWS user interface, select &lt;strong&gt;&lt;em&gt;new function&lt;/em&gt;&lt;/strong&gt; and select &lt;strong&gt;&lt;em&gt;Blank Function&lt;/em&gt;&lt;/strong&gt; from the blueprint list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure triggers
&lt;/h3&gt;

&lt;p&gt;Next, set a Trigger by clicking on the blank square and selecting &lt;strong&gt;&lt;em&gt;CloudWatch Events - Schedule&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2Faws-triggers-a3e919030adbdf84f0c2fc25abe7b9a0-5da69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2Faws-triggers-a3e919030adbdf84f0c2fc25abe7b9a0-5da69.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can set up your required CRON or defined rate from here. For now select Rate(1 day) to run this daily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2Faws-trigger2-b6addd022ed838ed0607e32228e691d5-02e4b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.john-mccracken.com%2Fstatic%2Faws-trigger2-b6addd022ed838ed0607e32228e691d5-02e4b.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Configure function
&lt;/h3&gt;

&lt;p&gt;Now give the Lambda a name, choose Python from the runtime list and then paste the contents of &lt;strong&gt;cf-security-group-update.py&lt;/strong&gt; from the &lt;a href="https://github.com/johnmccuk/cloudflare-ip-security-group-update" rel="noopener noreferrer"&gt;github code repository&lt;/a&gt; in the text area.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;&lt;em&gt;Environment variables&lt;/em&gt;&lt;/strong&gt; section, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;key: SECURITY_GROUP_ID
value: add your security group id here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;key: PORTS_LIST
value: 80,443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add &lt;strong&gt;80&lt;/strong&gt; or &lt;strong&gt;80,443&lt;/strong&gt; dependant on if you want http and https added to the security group.&lt;/p&gt;

&lt;p&gt;You may need to add a role in the &lt;strong&gt;&lt;em&gt;Lambda function handler and role&lt;/em&gt;&lt;/strong&gt; section. If so the only rule needed is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:DescribeSecurityGroups"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the &lt;strong&gt;&lt;em&gt;Timeout&lt;/em&gt;&lt;/strong&gt; to maybe 5-8 seconds.&lt;/p&gt;

&lt;p&gt;Keep the rest of the default values, continue and review, once happy finish by clicking &lt;strong&gt;&lt;em&gt;Create Function&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test
&lt;/h3&gt;

&lt;p&gt;Click the &lt;strong&gt;&lt;em&gt;Test&lt;/em&gt;&lt;/strong&gt; button and accept the defaults and the Lambda should hopefully work. The output should list the IP addresses added.&lt;/p&gt;

&lt;p&gt;To check it actually did add them, go back into the EC2 section and check your &lt;strong&gt;cloudflare-access&lt;/strong&gt; security group and hopefully it contains IP addresses. Try deleting some and running the Lambda again, it should replace them.&lt;/p&gt;

&lt;p&gt;There you go, you now have a Lambda function that will run routinely and will update the specified Security Group with any new CloudFlare IP addresses, Done!&lt;/p&gt;

&lt;h3&gt;
  
  
  Issues
&lt;/h3&gt;

&lt;p&gt;If it didn't work or you got error messages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare response error&lt;/strong&gt; - for some reason the cloudflare API wasn't available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failed to retrieve Security Group&lt;/strong&gt; - The Group ID used was incorrect.&lt;/li&gt;
&lt;li&gt;If the Lambda times out, click in the &lt;strong&gt;&lt;em&gt;Configuration&lt;/em&gt;&lt;/strong&gt; tab and set the &lt;strong&gt;&lt;em&gt;Timeout&lt;/em&gt;&lt;/strong&gt; to a higher value, 10 seconds should be adequate.&lt;/li&gt;
&lt;li&gt;Any other errors are probably due to the Security Role being incorrectly setup. Its &lt;a href="http://stackoverflow.com" rel="noopener noreferrer"&gt;Stack Overflow&lt;/a&gt; time!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Todo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add IPv6 addresses&lt;/li&gt;
&lt;li&gt;Remove old IP addresses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;sup&gt;Automate AWS security group with CloudFlare IPs first appeared on my &lt;a href="https://blog.john-mccracken.com" rel="noopener noreferrer"&gt;blog site&lt;/a&gt; on 04/04/2017.&lt;/sup&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>aws</category>
      <category>python</category>
    </item>
  </channel>
</rss>
