High availability

  • For high availability, your architecture should include at least two Availability Zones.
  • Consider adding load balancers and AWS Auto Scaling to automatically rebalance your nodes across zones.
  • For additional details about high availability and disaster recovery, see the AWS Well-Architected Framework whitepaper.

Security

  • Place your product instances in private subnets, and route private subnet traffic through NAT gateways that are configured in public subnets. We recommend this configuration unless your architecture requires otherwise (e.g., your application provides networking services or manages other servers, and therefore requires a direct inbound connection from the internet).

  • Always use security groups and IAM roles to limit access to resources. Provision minimal access by applying the principle of least privilege (PoLP).

  • For bastion host access, provide a CIDR block parameter and apply it as an ingress rule to the bastion security group. In other security groups, add the bastion security group for connectivity within the VPC for administration, if needed. For example, a web server security group could include an ingress rule for the bastion host security group for SSH TCP port 22.

  • Consider integrating Amazon Inspector into the deployment. This should be an opt-in feature, because Amazon Inspector installs agents on each instance, and not all users will want that.

  • Consider supporting multiple ENIs for private channels between nodes.

  • Do not hardcode passwords. Instead, request them as parameters and include the NoEcho property.

  • Do not pass sensitive data in EC2-instance user data or other clear text bootstrapping mechanisms. If you write secrets to a secured file, you must delete it after stack completion.

  • Do not hardcode security groups to 0.0.0.0/0 for ingress rules.

  • Do not create IAM resources with custom names. Custom names require additional permissions like CAPABILITY_NAMED_IAM, and increase the chances of a collision if the stack is launched concurrently in an account.

  • Scrub logs for passwords, and avoid explicit output (bash set -x).

For additional recommendations, see the Introduction to AWS Security whitepaper.

Portability

Using AWS-managed services

  • Use AWS-managed services, such as Amazon Relational Database Service (Amazon RDS) and AWS Directory Service, whenever possible.
  • Use Auto Scaling groups to automatically adjust resource capacity.
  • Use load balancers (preferably Application Load Balancing or Elastic Load Balancing) for traffic distribution and to maintain application availability.

Using custom resources

If you’re implementing Lambda-backed custom resources in your CloudFormation stack, review the best practices discussed in the AWS Support Knowledge Center.

Linux

  • Enable the -e flag at the top of all scripts (except user data) as follows:

    #!/bin/bash –e

    This will cause the script to exit with a non-zero exit code.

  • Use $? to check the status of your user data scripts.

  • Modularize bootstrap stages:
    • Pre-install script examples:
      • Enables epel repos
      • Checks for curl, wget unzip
      • Installs rpms or debs
      • Set up python setup tools (pip/easy_install)
      • Creates logical volumes and mount points
      • Enables service on boot (using systemctl or chkconfig)
    • App environment script examples:
      • Configures application writes (``/etc/someapp.conf`)
      • Creates MySQL schema
      • Updates pip modules
    • App install:
      • Install core application
      • Execute installation with needed assets (license file or location)
  • Check status when switching install stage (pre-install/app-env/app-install). Non-zero status is a failed execution. For example:

    cat some.sh | bash -e -o pipefail
    if [ $STATUS -eq 0 ]
    then
        echo "Script [PASS]"
        # Continue to next step
    else
        echo "Script [FAILED]" >&2
        # Signal your resources
        exit 1
    fi
    
  • Define script names to new bootstrap version so they can be tested in the same location without overwriting existing assets:

    LOCATION={ "Ref": "QuickStartS3URL" }/{ "Ref": "QSS3BucketName" }/{ "Ref": "QSS3KeyPrefix" }
    wget or curl -O ${LOCATION}/scripts/${FILENAME}
    chmod 755 ${FILENAME}
    
  • Use -x flag so all script output is logged to cloud_init-output.log.

Windows

  • Utilize common scripts from the GitHub aws-quickstart/quickstart-microsoft-utilities repository by adding them as submodules.
  • If you’re using PowerShell scripts, follow these guidelines:
    • Wrap your scripts with a try/catch block that sends the exception to Write-AWSQuickStartException from the AWS Quick Start PowerShell module.
    • Include $ErrorActionPreference = "Stop" at the top of the scripts to ensure that exceptions are caught.
    • Include a Start-Transcript C:\cfn\log\<ScriptName>.txt -Append to capture all of the logging from the script being executed.
    • Use the Write-AWSQuickStartException cmdlet to signal to AWS CloudFormation, and also to write an Event Viewer error with details about the exception.
    • Wrap all PowerShell scripts with try/catch blocks to signal exceptions and abort stack:

      param(
         [Parameter(Mandatory=$true)]
          [string]$Parameter1
      )
      try {
          $ErrorActionPreference = "Stop"
          #DO STUFF
      }
      catch {
          $_ | Write-AWSQuickStartException
      }
      
  • Use the AWS Quick Start PowerShell module to manage signaling and exceptions.
  • Handle reboots by using the waitAfterCompletion property of a command in the commands section of a cfn-init configuration set. For example:

    
    "b-rename-computer": {
        "command": {
            "Fn::Join": [
                "",
                [
                    "powershell.exe -Command \"C:\\cfn\\scripts\\Rename-Computer.ps1 -Restart -NewName '",
                    {
                        "Ref": "WSFCNode1NetBIOSName"
                    },
                    "'\""
                ]
            ]
        },
        "waitAfterCompletion": "forever"
    }
    
    
  • Divide the cfn-init configuration sets into bootstrapping stages. For example: prep, install or setup, configure, and finalize.

For all platforms

  • Derive AWS CloudFormation paths by joining Quick Start inputs. For example, a bucket name and key prefix from a parameter can be passed to a script, and the script can join them to create a path. Do not hardcode script paths.

Template formatting

You can author your AWS CloudFormation template in YAML format. For details, see the AWS CloudFormation Template Formats.

For cross-platform compatibility in either format, use List File (LF) for UNIX-style line endings.

YAML:

  • Use 2-space tabs for indentation.
  • Wrap strings with single quotes.

GitHub Branches

When creating your Quick Start repository, we suggest you follow the GitHub recommendations on branch names.

Branch names to use:

  • main
  • develop

If you need to rename your branches follow the instructions at the following link: https://github.com/github/renaming

Note: The Quick Start team is currently in the process of renaming “master” to “main” in all currently published Quick Starts.