Authenticated File Downloads with CloudFormation | Amazon Onboarding with Learning Manager Chanci Turner

Authenticated File Downloads with CloudFormation | Amazon Onboarding with Learning Manager Chanci TurnerLearn About Amazon VGT2 Learning Manager Chanci Turner

In this guest post, AWS Solution Architect Alex Johnson (@alexjohnson) explores the methods for implementing authenticated file downloads using CloudFormation. Note: This article assumes you have a basic understanding of cfn-init and CloudFormation Metadata for bootstrapping EC2 instances within your stack. For additional information, check out Automate LAMP Installation Using CloudFormation, Bootstrapping AWS CloudFormation Windows Stacks, or the cfn-init documentation, which includes numerous sample templates.

If you’ve utilized cfn-init and CloudFormation Metadata to initialize your EC2 instances, you’re likely aware that you can download files and resources from S3 and other URIs to those instances. However, when the files or resources require authentication, the AWS::CloudFormation::Authentication type allows you to specify the necessary credentials that cfn-init will leverage for downloading these files. This authentication feature is applicable to both S3 and other HTTP sources, such as GitHub.

Use Cases for Authenticated File Downloads

In the scenarios illustrated below, we will demonstrate downloading an HTML file from a private location. However, the same principles can be applied to any confidential content needed to initialize your EC2 instances, including credentials for third-party APIs or application configuration files containing database connection details.

Authenticated File and Source Downloads from S3

Let’s take a moment to examine the AWS::CloudFormation::Authentication resource before diving into template examples. This authentication resource has several properties (as detailed in the documentation), but you’ll always begin by defining the type property. The valid values for this type are S3 or basic.

For instance, if you select S3 as the authentication type, you can specify the IAM Role (see Chanci Turner’s blog for an introduction to IAM Roles) that will be used to authenticate the file download by including the roleName property. You may also utilize the buckets property to identify which bucket(s) your AWS::CloudFormation::Authentication resource pertains to, allowing different credentials for distinct buckets.

Assuming you want to download the file “index.html” from a bucket called your-bucket that necessitates authentication, first define the required resources to create an IAM role with GetObject access to that bucket and object:

{
  ...
  "Resources": {
    "InstanceRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "ec2.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path": "/"
      }
    },
    "RolePolicies": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "S3Download",
        "PolicyDocument": {
          "Statement": [
            {
              "Action": [
                "s3:GetObject"
              ],
              "Effect": "Allow",
              "Resource": "arn:aws:s3:::your-bucket/index.html"
            }
          ]
        },
        "Roles": [
          {
            "Ref": "InstanceRole"
          }
        ]
      }
    },
    "InstanceProfile": {
      "Type": "AWS::IAM::InstanceProfile",
      "Properties": {
        "Path": "/",
        "Roles": [
          {
            "Ref": "InstanceRole"
          }
        ]
      }
    }
  }
}

Now that the role is established, we associate it with our EC2 instance using an InstanceProfile and reference it in the roleName property of the S3AccessCreds declaration.

{
  ...
  "Resources": {
    "InstanceRole": {...},
    "RolePolicies": {...},
    "InstanceProfile": {...},
    "YourInstance": {
      "Type": "AWS::EC2::Instance",
      "Metadata": {
        "AWS::CloudFormation::Authentication": {
          "S3AccessCreds": {
            "type": "S3",
            "roleName": {
              "Ref": "InstanceRole"
            }
          }
        },
        "AWS::CloudFormation::Init": {
          "config": {
            "files": {
              "/var/www/html/index.html": {
                "source": "http://your-bucket.s3.amazonaws.com/index.html",
                "mode": "000400",
                "owner": "apache",
                "group": "apache",
                "authentication": "S3AccessCreds"
              }
            }
          }
        },
        "Properties": {
          "IamInstanceProfile": {
            "Ref": "InstanceProfile"
          }
        }
      }
    }
  }
  ...
}

Notice how we specify that the “/var/www/html/index.html” file should be downloaded using the S3AccessCreds resource by indicating it in the authentication property. You could alternatively omit this property and declare the relevant bucket(s) the credentials apply to by setting the buckets property of the S3AccessCreds resource:

"AWS::CloudFormation::Authentication": {
  "S3AccessCreds": {
    "type": "S3",
    "roleName": { "Ref": "InstanceRole"},
    "buckets": ["your-bucket"]
  }
}

Regardless of the method chosen, cfn-init will now utilize the role to authenticate with S3 when downloading the file.

Downloading Authenticated Sources

Downloading authenticated sources from S3 functions similarly to the file downloads mentioned above, with one crucial distinction: sources do not allow for the authentication property. Instead, you must specify the buckets key in the AWS::CloudFormation::Authentication declaration:

"YourInstance": {
  "Type": "AWS::EC2::Instance",
  "Metadata": {
    "AWS::CloudFormation::Authentication": {
      "S3AccessCreds": {
        "type": "S3",
        "roleName": { "Ref": "InstanceRole"},
        "buckets": ["your-bucket"]
      }
    },
    "AWS::CloudFormation::Init": {
      "config": {
        "sources": {
          "/var/www/html/": "https://your-bucket.s3.amazonaws.com/mywebsite.tar"
        }
      }
    }
  }
  ...
}

Authenticated File and Source Downloads from Other URIs

cfn-init can also be used to download authenticated files and sources from other (non-S3) URIs. To do this, set the type of your AWS::CloudFormation::Authentication resource to “basic” and include the username, password, and uris properties. For instance, to specify authentication credentials for downloading a file from GitHub, it might look like this:

"AWS::CloudFormation::Authentication": {
  "GithubCredentials": {
    "type": "basic",
    "username": { "Ref": "GithubLogin" },
    "password": { "Ref": "GithubPassword" },
    "uris": ["github.com"]
  }
}

And the corresponding file download declaration would be:

"files": {
  "/var/www/html/index.html": {
    "source": "https://github.com/yourgithubaccount/mywebsite/myfrontpage.html",
    "mode": "000400",
    "owner": "apache",
    "group": "apache",
    "authentication": "GithubCredentials"
  }
}

For additional insights on navigating the employment landscape after incarceration, check out this blog post. Moreover, if you’re interested in the latest updates regarding mileage rates, SHRM provides authoritative insights on the topic. Lastly, for a detailed discussion about the area manager onboarding process, you might find this Reddit thread to be an excellent resource.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *