Skip to content

Commit

Permalink
Merge pull request #57 from caktus/develop
Browse files Browse the repository at this point in the history
Release 1.4.0
  • Loading branch information
copelco authored Aug 5, 2019
2 parents 10c789a + 94067ab commit a43a7a2
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 33 deletions.
41 changes: 41 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
version: 2
jobs:
build:
docker:
- image: circleci/python:3.5
steps:
- restore_cache:
keys:
- source-v1-{{ .Branch }}-{{ .Revision }}
- source-v1-{{ .Branch }}-
- source-v1-
- checkout
- save_cache:
key: source-v2-{{ .Branch }}-{{ .Revision }}
paths:
- ".git"
- restore_cache:
key: pip-v1-{{ checksum "requirements.txt" }}-{{ checksum "requirements.txt" }}
- run:
name: Set up python environment
command: |
python3 -m venv env
. env/bin/activate
pip install -U -r requirements.txt
pip install -U awscli
- save_cache:
key: pip-v1-{{ checksum "requirements.txt" }}-{{ checksum "requirements.txt" }}
paths:
- "env"
- run:
name: Build, check, and upload templates to S3
command: |
. env/bin/activate
make templates
make check
- deploy:
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
. env/bin/activate
make upload
fi
22 changes: 22 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
Change Log
==========


`X.Y.Z`_ (TBD-DD-DD)
---------------------

* TBD


`1.4.0`_ (2019-08-05)
---------------------

Features:

* Allow ACM certificate to be optional and/or be specified at a later date via a manual process. See
Manual ACM Certificates in README for more information.
* Adds AdministratorIPAddress parameter so SSH access can be configured (thanks @dsummersl).
* Adds AssetsUseAES256Encryption parameter to enable AES256 encryption on asset buckets (thanks @dsummersl).
* Adds IgnorePublicAcls setting to private access buckets.
* Upgrade Circle CI to 2.0
* Miscellaneous fixes for release (thanks @cchurch)


`1.3.0`_ (2018-09-13)
---------------------

Expand Down Expand Up @@ -134,6 +155,7 @@ Backwards-incompatible changes:
* Initial public release


.. _1.4.0: https://aws-web-stacks.s3.amazonaws.com/index.html?prefix=1.4.0/
.. _1.3.0: https://aws-web-stacks.s3.amazonaws.com/index.html?prefix=1.3.0/
.. _1.2.0: https://aws-web-stacks.s3.amazonaws.com/index.html?prefix=1.2.0/
.. _1.1.2: https://aws-web-stacks.s3.amazonaws.com/index.html?prefix=1.1.2/
Expand Down
26 changes: 26 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,32 @@ query) and follow the link to approve the certificate. If you're using a ``.io``
may be necessary to receive email for ``.io`` domains, because domain owner emails cannot
be discovered via ``whois``.

Manual ACM Certificates
~~~~~~~~~~~~~~~~~~~~~~~

You also have the option to *not* create a certificate as part of the stack provisioning process. If
you do this, an HTTPS listener (and corresponding certificate) can be manually attached to the load
balancer after stack creation via the AWS Console or using ``awscli`` using the steps below.

To request a new certificate using DNS validation, run the following command with ``--domain-name``
matching your desired domain::

aws acm request-certificate --domain-name [DOMAIN NAME] --validation-method DNS

You can query the CNAME ``name`` and ``value`` variables using ``describe-certificate``::

aws acm list-certificates
aws acm describe-certificate --certificate-arn=YOUR-CertificateArn

Add the listed CNAME to your DNS provider to complete the verification process.

Once verified, add an HTTPS listener to the environment's ELB::

aws elb describe-load-balancers --query "LoadBalancerDescriptions[*].LoadBalancerName"
aws elb create-load-balancer-listeners --load-balancer-name [LB NAME]
--listeners "SSLCertificateId=[CERTIFICATE-ARN],Protocol=HTTPS,LoadBalancerPort=443,InstanceProtocol=HTTP,InstancePort=80"


Resources Created
-----------------

Expand Down
18 changes: 0 additions & 18 deletions circle.yml

This file was deleted.

2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
awacs==0.8.1
troposphere==2.3.3
troposphere==2.4.5
flake8==3.4.1
isort==4.2.15
sphinx==1.6.7
41 changes: 39 additions & 2 deletions stack/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@
DistributionConfig,
ForwardedValues,
Origin,
S3Origin,
S3OriginConfig,
ViewerCertificate
)
from troposphere.s3 import (
Bucket,
BucketEncryption,
CorsConfiguration,
CorsRules,
Private,
PublicAccessBlockConfiguration,
PublicRead,
ServerSideEncryptionByDefault,
ServerSideEncryptionRule,
VersioningConfiguration
)

Expand All @@ -37,7 +41,37 @@
from .template import template
from .utils import ParameterWithDefaults as Parameter

use_aes256_encryption = template.add_parameter(
Parameter(
"AssetsUseAES256Encryption",
Description="Whether or not to use server side encryption for S3 buckets. "
"When true, AES256 encryption is enabled for all asset buckets.",
Type="String",
AllowedValues=["true", "false"],
Default="false",
),
group="Static Media",
label="Enable AES256 Encryption",
)
use_aes256_encryption_cond = "AssetsUseS3EncryptionCondition"
template.add_condition(use_aes256_encryption_cond, Equals(Ref(use_aes256_encryption), "true"))

common_bucket_conf = dict(
BucketEncryption=BucketEncryption(
ServerSideEncryptionConfiguration=If(
use_aes256_encryption_cond,
[
ServerSideEncryptionRule(
ServerSideEncryptionByDefault=ServerSideEncryptionByDefault(
SSEAlgorithm='AES256'
)
)
],
[
ServerSideEncryptionRule()
]
)
),
VersioningConfiguration=VersioningConfiguration(
Status="Enabled"
),
Expand Down Expand Up @@ -93,6 +127,9 @@
Bucket(
"PrivateAssetsBucket",
AccessControl=Private,
PublicAccessBlockConfiguration=PublicAccessBlockConfiguration(
IgnorePublicAcls=True
),
**common_bucket_conf,
)
)
Expand Down Expand Up @@ -228,7 +265,7 @@
Origins=[Origin(
Id="Assets",
DomainName=GetAtt(assets_bucket, "DomainName"),
S3OriginConfig=S3Origin(
S3OriginConfig=S3OriginConfig(
OriginAccessIdentity="",
),
)],
Expand Down
16 changes: 12 additions & 4 deletions stack/certificates.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Note: GovCloud doesn't support the certificate manager, so this file is
# only imported from load_balancer.py when we're not using GovCloud.

from troposphere import If, Ref
from troposphere import Equals, If, Not, Ref
from troposphere.certificatemanager import Certificate, DomainValidationOption

from .common import dont_create_value
from .domain import domain_name, domain_name_alternates, no_alt_domains
from .template import template
from .utils import ParameterWithDefaults as Parameter
Expand All @@ -12,20 +13,27 @@
Parameter(
title="CertificateValidationMethod",
Default="DNS",
AllowedValues=['DNS', 'Email'],
AllowedValues=[dont_create_value, 'DNS', 'Email'],
Type='String',
Description=""
"How to validate domain ownership for issuing an SSL certificate - "
"highly recommend DNS. Either way, stack creation will pause until "
"you do something to complete the validation."
"highly recommend DNS. DNS and Email will pause stack creation until "
"you do something to complete the validation. If omitted, an HTTPS "
"listener can be manually attached to the load balancer after stack "
"creation."
),
group="Global",
label="Certificate Validation Method"
)

cert_condition = "CertificateCondition"
template.add_condition(cert_condition,
Not(Equals(Ref(certificate_validation_method), dont_create_value)))

application = Ref(template.add_resource(
Certificate(
'Certificate',
Condition=cert_condition,
DomainName=domain_name,
SubjectAlternativeNames=If(no_alt_domains, Ref("AWS::NoValue"), domain_name_alternates),
DomainValidationOptions=[
Expand Down
13 changes: 13 additions & 0 deletions stack/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@
template.add_condition(in_govcloud_region, Equals(Ref(AWS_REGION), "us-gov-west-1"))
arn_prefix = If(in_govcloud_region, "arn:aws-us-gov", "arn:aws")

administrator_ip_address = Ref(template.add_parameter(
Parameter(
"AdministratorIPAddress",
Description="The IP address allowed to access containers. "
"Defaults to TEST-NET-1 (ie, no valid IP)",
Type="String",
# RFC5737 - TEST-NET-1 reserved for documentation
Default="192.0.2.0/24",
),
group="Application Server",
label="Admin IP Address",
))

container_instance_type = Ref(template.add_parameter(
Parameter(
"ContainerInstanceType",
Expand Down
7 changes: 4 additions & 3 deletions stack/load_balancer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os

from troposphere import elasticloadbalancing as elb
from troposphere import GetAtt, Join, Output, Ref
from troposphere import GetAtt, If, Join, Output, Ref

from .security_groups import load_balancer_security_group
from .template import template
Expand Down Expand Up @@ -107,13 +107,14 @@
))
else:
from .certificates import application as application_certificate
listeners.append(elb.Listener(
from .certificates import cert_condition
listeners.append(If(cert_condition, elb.Listener(
LoadBalancerPort=443,
InstanceProtocol=web_worker_protocol,
InstancePort=web_worker_port,
Protocol='HTTPS',
SSLCertificateId=application_certificate,
))
), Ref("AWS::NoValue")))

load_balancer = elb.LoadBalancer(
'LoadBalancer',
Expand Down
19 changes: 15 additions & 4 deletions stack/security_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from troposphere import Ref
from troposphere.ec2 import SecurityGroup, SecurityGroupRule

from .common import administrator_ip_address
from .template import template
from .vpc import loadbalancer_a_subnet_cidr, loadbalancer_b_subnet_cidr, vpc

Expand Down Expand Up @@ -48,12 +49,22 @@
) for port, cidr in product(*[web_worker_ports, cidrs])]

# Health check
if os.environ.get('USE_EB') != 'on':
ingress_rules.append(SecurityGroupRule(
IpProtocol="tcp",
FromPort=Ref("WebWorkerHealthCheckPort"),
ToPort=Ref("WebWorkerHealthCheckPort"),
Description="ELB Health Check", # SecurityGroupRule doesn't support a Description attribute
SourceSecurityGroupId=Ref(load_balancer_security_group),
))

# AdministratorAccess
ingress_rules.append(SecurityGroupRule(
IpProtocol="tcp",
FromPort=Ref("WebWorkerHealthCheckPort"),
ToPort=Ref("WebWorkerHealthCheckPort"),
# Description="ELB Health Check", # SecurityGroupRule doesn't support a Description attribute
SourceSecurityGroupId=Ref(load_balancer_security_group),
FromPort="22",
ToPort="22",
Description="Administrator SSH Access",
CidrIp=administrator_ip_address,
))

container_security_group = SecurityGroup(
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.3.0
1.4.0

0 comments on commit a43a7a2

Please sign in to comment.