Skip to content

Latest commit

 

History

History
221 lines (188 loc) · 5.42 KB

cfn-customization.md

File metadata and controls

221 lines (188 loc) · 5.42 KB

CloudFormation customizations

Porter allows services to define the subset of a CloudFormation (CFN) template that they want to be different than what porter creates by default.

The basic rule is that porter won't alter defined resources and properties on those resources. There are some exceptions for properties that are lists (like EC2 tags).

Some simple examples are below. Porter injects various CFN parameters such as PorterServiceName and PorterEnvironment. Additionally there are a number of intrinsic functions and psuedo parameters that can provide additional data and make all sort of template customizations possible, including creating conditional resources

Some projects are finding they can use a single template to deploy all of their microservcies, which don't vary much from one another.

Finally, with porter hooks, you could even create a CFN template on the fly as part of a deployment pipeline. See the pre-pack hook for more.

Examples

For all examples we'll use the following .porter/config and just change .porter/cfn.json in each example.

service_name: zero2porter

porter_version: v0.61.1

containers:
- topology: inet

environments:
- name: PROD

  stack_definition_path: .porter/cfn.json

  regions:
  - name: us-west-2
    azs:
    - name: us-west-2a
    - name: us-west-2b
    - name: us-west-2c

    role_arn: arn:aws:iam::123456789012:role/zero2porter-deployment
    s3_bucket: zero2porter-us-west-2

    elb: zero2porter-prod

Examples

SSH

This is probably the first customization every service operator needs, SSH access. Porter adds all the resources not already defined in order to create a working CloudFormation template which means the AWS::AutoScaling::LaunchConfiguration isn't overwritten, and security groups are added to the SecurityGroups property already defined.

Note: this is the complete CloudFormation template

.porter/cfn.json

{
  "Resources": {
    "AutoScalingLaunchConfiguration": {
      "Type": "AWS::AutoScaling::LaunchConfiguration",
      "Properties": {
        "SecurityGroups": [
          {
            "Ref": "SSHSecurityGroup"
          }
        ]
      }
    },
    "SSHSecurityGroup": {
      "Properties": {
        "GroupDescription": "Enable SSH access to EC2 hosts",
        "SecurityGroupIngress": [
          {
            "CidrIp": "8.8.8.8/32",
            "FromPort": 22,
            "IpProtocol": "tcp",
            "ToPort": 22
          }
        ]
      },
      "Type": "AWS::EC2::SecurityGroup"
    }
  }
}

Custom AMIs

Another common customization is to provide different AMIs. Porter defaults to using Amazon Linux AMI so for the best results, custom AMIs should be based on Amazon Linux AMI.

Again, porter doesn't redefined the AWS::AutoScaling::LaunchConfiguration resource, and because ImageId is defined, porter leaves it alone.

.porter/cfn.json for a single region

{
  "Resources": {
    "AutoScalingLaunchConfiguration": {
      "Type": "AWS::AutoScaling::LaunchConfiguration",
      "Properties": {
        "ImageId": "ami-abcd1234"
      }
    }
  }
}

.porter/cfn.json for multi-region

{
  "Mappings": {
    "RegionToCustomAMI": {
      "ap-northeast-1": {
        "Key": "ami-abcd1234"
      },
      "ap-northeast-2": {
        "Key": "ami-abcd1235"
      },
      "ap-southeast-1": {
        "Key": "ami-abcd1236"
      },
      "ap-southeast-2": {
        "Key": "ami-abcd1237"
      },
      "eu-central-1": {
        "Key": "ami-abcd1238"
      },
      "eu-west-1": {
        "Key": "ami-abcd1239"
      },
      "sa-east-1": {
        "Key": "ami-abcd1240"
      },
      "us-east-1": {
        "Key": "ami-abcd1241"
      },
      "us-west-1": {
        "Key": "ami-abcd1242"
      },
      "us-west-2": {
        "Key": "ami-abcd1243"
      }
    }
  },
  "Resources": {
    "AutoScalingLaunchConfiguration": {
      "Type": "AWS::AutoScaling::LaunchConfiguration",
      "Properties": {
        "ImageId": {
          "Fn::FindInMap": [
            "RegionToCustomAMI",
            {
              "Ref": "AWS::Region"
            },
            "Key"
          ]
        }
      }
    }
  }
}

Additional EC2 permissions

A service often interacts with other AWS services and needs permission to do so. Here is an example enabling EC2 instances to query a madeup DynamoDB table called books_table

.porter/cfn.json

{
  "Resources": {
    "EC2Role": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "Policies": [
          {
            "PolicyDocument": {
              "Statement": [
                {
                  "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/books_table",
                  "Action": [
                    "dynamodb:GetItem",
                    "dynamodb:Query"
                  ],
                  "Effect": "Allow"
                }
              ]
            }
          }
        ]
      }
    }
  }
}