Last active
March 21, 2019 19:16
-
-
Save alexjurkiewicz/c7e171cd8abc1e1b8628d63c69531ead to your computer and use it in GitHub Desktop.
Verdaccio CloudFormation template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Instructions: | |
# 1. Check all "TODO" comments and make changes if required for your environment | |
# 2. Provide values for all required parameters and any optional parameters desired | |
AWSTemplateFormatVersion: '2010-09-09' | |
Description: Verdaccio - NPM cache / private registry | |
Parameters: | |
# REQUIRED PARAMETERS | |
Ami: | |
Type: AWS::EC2::Image::Id | |
Description: > | |
Amazon Linux 2 AMI ID for the proxy instances. Find it with | |
'aws ssm get-parameters --names /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' | |
Ec2KeyPair: | |
Type: String | |
Description: EC2 Key Pair to use for the proxy instances. | |
HttpsCertificateArn: | |
Type: String | |
Description: ACM certificate ARN to use | |
DnsHostedZoneName: | |
Type: String | |
Description: > | |
The route 53 hosted zone name to create the `npm.<zone>` record in. Do not | |
include the trailing dot! | |
Route53RecordHostedZoneId: | |
Type: String | |
Description: > | |
Hosted Zone ID for the load balancer. Find it here: | |
https://docs.aws.amazon.com/general/latest/gr/rande.html | |
Vpc: | |
Type: AWS::EC2::VPC::Id | |
Description: VPC to create this stack inside | |
AsgSubnets: | |
Type: List<AWS::EC2::Subnet::Id> | |
Description: > | |
Subnets the auto scaling group should span. | |
LbSubnets: | |
Type: List<AWS::EC2::Subnet::Id> | |
Description: > | |
Subnets the load balancer should span. | |
VerdaccioConfigUrl: | |
Type: String | |
Description: URL the ASG instances can download Verdaccio's config.yaml from. | |
VerdaccioHtpasswdUrl: | |
Type: String | |
Description: URL the ASG instances can download Verdaccio's htpasswd from. | |
# OPTIONAL PARAMETERS | |
DockerImage: | |
Type: String | |
Default: verdaccio/verdaccio:3 | |
AsgMinSize: | |
Type: String | |
Default: "1" | |
AsgMaxSize: | |
Type: String | |
Default: "1" | |
AsgInstanceType: | |
Type: String | |
Default: t3.nano | |
DnsName: | |
Type: String | |
Default: npm | |
Description: The Route 53 record created is $DnsName.$DnsHostedZoneName | |
Resources: | |
Asg: | |
Type: AWS::AutoScaling::AutoScalingGroup | |
DependsOn: | |
- EfsMountA | |
- EfsMountB | |
- EfsMountC | |
Properties: | |
DesiredCapacity: | |
Ref: AsgMaxSize | |
HealthCheckGracePeriod: 60 | |
HealthCheckType: ELB | |
LaunchConfigurationName: | |
Ref: Lc | |
MaxSize: | |
Ref: AsgMinSize | |
MinSize: | |
Ref: AsgMaxSize | |
Tags: | |
- Key: Name | |
Value: | |
Ref: AWS::StackName | |
PropagateAtLaunch: true | |
TargetGroupARNs: | |
- Ref: Tg | |
VPCZoneIdentifier: | |
Ref: AsgSubnets | |
# TODO: you may want to add target tracking scaling policy. By default the ASG | |
# does not automatically scale. | |
AsgSg: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: Used by instances in the Auto Scaling Group. | |
SecurityGroupIngress: | |
- FromPort: 22 | |
ToPort: 22 | |
IpProtocol: tcp | |
# TODO: you may want to restrict the IP range or change to SourceSecurityGroupId | |
CidrIp: 0.0.0.0/0 | |
SecurityGroupEgress: | |
- FromPort: 0 | |
ToPort: 65535 | |
IpProtocol: tcp | |
CidrIp: 0.0.0.0/0 | |
Tags: | |
- Key: Name | |
Value: | |
Fn::Sub: ${AWS::StackName} ASG | |
VpcId: | |
Ref: Vpc | |
AsgSgHttpIngress: | |
Type: AWS::EC2::SecurityGroupIngress | |
Properties: | |
GroupId: | |
Ref: AsgSg | |
FromPort: 4873 | |
ToPort: 4873 | |
IpProtocol: tcp | |
SourceSecurityGroupId: | |
Ref: LbSg | |
Lc: | |
Type: AWS::AutoScaling::LaunchConfiguration | |
Properties: | |
ImageId: | |
Ref: Ami | |
InstanceType: | |
Ref: AsgInstanceType | |
KeyName: | |
Ref: Ec2KeyPair | |
SecurityGroups: | |
- Ref: AsgSg | |
UserData: | |
Fn::Base64: | |
# Since this uses Fn::Sub, don't use the ${var} form for any bash | |
# variables. Just use $var. | |
Fn::Sub: | | |
#!/bin/bash | |
set -eu | |
start_time=$(date +%s) | |
IMAGE="${DockerImage}" | |
BASE="/verdaccio" | |
# Mount EFS first | |
yum -y install amazon-efs-utils | |
mkdir /verdaccio | |
echo "${Efs}:/ "$BASE" efs tls,_netdev" >> /etc/fstab | |
mount -a -t efs defaults | |
# Create/update the config & password files. | |
mkdir "$BASE/conf" | |
curl -o "$BASE/conf/htpasswd" "${VerdaccioHtpasswdUrl}" | |
curl -o "$BASE/conf/config.yaml" "${VerdaccioConfigUrl}" | |
amazon-linux-extras install docker | |
systemctl start docker | |
# Download the image | |
docker pull "$IMAGE" | |
# Update permissions on the cache directory. | |
target_uid=$(docker run "$IMAGE" id -u) | |
target_gid=$(docker run "$IMAGE" id -g) | |
chown "$target_uid:$target_gid" "$BASE" | |
docker run --detach \ | |
-p 4873:4873 \ | |
--mount "type=bind,src=$BASE,dst=/verdaccio" \ | |
"$IMAGE" | |
echo "Finished user-data script in $(( $(date +%s) - start_time)) secs" | |
Tg: | |
Type: AWS::ElasticLoadBalancingV2::TargetGroup | |
Properties: | |
HealthCheckIntervalSeconds: 5 | |
HealthCheckPort: "4873" | |
HealthCheckProtocol: "HTTP" | |
HealthCheckTimeoutSeconds: 2 | |
Port: 4873 | |
Protocol: "HTTP" | |
TargetGroupAttributes: | |
- Key: deregistration_delay.timeout_seconds | |
Value: "10" | |
VpcId: | |
Ref: Vpc | |
Lb: | |
Type: AWS::ElasticLoadBalancingV2::LoadBalancer | |
Properties: | |
SecurityGroups: | |
- Ref: LbSg | |
Subnets: | |
Ref: LbSubnets | |
Tags: | |
- Key: Name | |
Value: | |
Fn::Sub: ${AWS::StackName} ALB | |
LbSg: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: | |
Fn::Sub: Allow HTTPS connections to the ${AWS::StackName} load balancer | |
SecurityGroupIngress: | |
# TODO: Add any required ingress IPs | |
- FromPort: 443 | |
ToPort: 443 | |
IpProtocol: tcp | |
CidrIp: 10.0.0.0/8 | |
Tags: | |
- Key: Name | |
Value: | |
Fn::Sub: ${AWS::StackName} LB | |
VpcId: | |
Ref: Vpc | |
LbSgHttpEgress: | |
Type: AWS::EC2::SecurityGroupEgress | |
Properties: | |
GroupId: | |
Ref: LbSg | |
FromPort: 4873 | |
ToPort: 4873 | |
IpProtocol: tcp | |
DestinationSecurityGroupId: | |
Ref: AsgSg | |
LbListener: | |
Type: AWS::ElasticLoadBalancingV2::Listener | |
Properties: | |
Certificates: | |
- CertificateArn: | |
Ref: HttpsCertificateArn | |
DefaultActions: | |
- TargetGroupArn: | |
Ref: Tg | |
Type: forward | |
LoadBalancerArn: | |
Ref: Lb | |
Port: 443 | |
Protocol: HTTPS | |
SslPolicy: ELBSecurityPolicy-TLS-1-2-2017-01 | |
Dns: | |
Type: AWS::Route53::RecordSet | |
Properties: | |
AliasTarget: | |
DNSName: | |
Fn::GetAtt: | |
- Lb | |
- DNSName | |
HostedZoneId: | |
Ref: Route53RecordHostedZoneId | |
HostedZoneName: | |
Fn::Sub: ${DnsHostedZoneName}. | |
Name: | |
Fn::Sub: ${DnsName}.${DnsHostedZoneName}. | |
Type: A | |
Efs: | |
Type: AWS::EFS::FileSystem | |
Properties: | |
FileSystemTags: | |
- Key: Name | |
Value: | |
Ref: AWS::StackName | |
EfsSg: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: | |
Fn::Sub: Allow connections from the ${AWS::StackName} ASG | |
Tags: | |
- Key: Name | |
Value: | |
Fn::Sub: ${AWS::StackName} EFS | |
VpcId: | |
Ref: Vpc | |
EfsSgFsIngress: | |
Type: AWS::EC2::SecurityGroupIngress | |
Properties: | |
GroupId: | |
Ref: EfsSg | |
FromPort: 2049 | |
ToPort: 2049 | |
IpProtocol: tcp | |
SourceSecurityGroupId: | |
Ref: AsgSg | |
# TODO: if you have more / less than three subnets for AsgSubnets, add/delete | |
# entries here as appropriate. Also update the DependsOn section of Asg | |
# resource. | |
EfsMountA: | |
Type: AWS::EFS::MountTarget | |
Properties: | |
FileSystemId: | |
Ref: Efs | |
SecurityGroups: | |
- Ref: EfsSg | |
SubnetId: | |
Fn::Select: | |
- 0 | |
- Ref: AsgSubnets | |
EfsMountB: | |
Type: AWS::EFS::MountTarget | |
Properties: | |
FileSystemId: | |
Ref: Efs | |
SecurityGroups: | |
- Ref: EfsSg | |
SubnetId: | |
Fn::Select: | |
- 1 | |
- Ref: AsgSubnets | |
EfsMountC: | |
Type: AWS::EFS::MountTarget | |
Properties: | |
FileSystemId: | |
Ref: Efs | |
SecurityGroups: | |
- Ref: EfsSg | |
SubnetId: | |
Fn::Select: | |
- 2 | |
- Ref: AsgSubnets | |
Outputs: | |
Hostname: | |
Value: | |
Ref: Dns |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment