322 lines
12 KiB
JSON
322 lines
12 KiB
JSON
{
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
"Parameters" : {
|
|
"InstanceTypeParameter" : {
|
|
"Type" : "String",
|
|
"Default" : "t3.large",
|
|
"AllowedValues" : ["t2.micro", "t3.micro", "m1.small", "m5.small", "m1.large", "m5.large", "t2.large", "t3.large"],
|
|
"Description" : "Type of EC2 instance you want to run your master in."
|
|
},
|
|
"KeyNameParameter": {
|
|
"Type": "AWS::EC2::KeyPair::KeyName",
|
|
"Description": "The KeyName that will be used to access this EC2 instance."
|
|
},
|
|
"PrivateKey": {
|
|
"Type" : "String",
|
|
"Description" : "The private key for the keypair specified above (required to access agents from master)."
|
|
},
|
|
"SSHLocation" : {
|
|
"Description" : "The IP address range that can be used to SSH to the EC2 instance for your Jenkins Evergreen instance.",
|
|
"Type": "String",
|
|
"MinLength": "9",
|
|
"MaxLength": "18",
|
|
"AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
|
|
"ConstraintDescription": "Must be a valid IP CIDR range of the form x.x.x.x/x"
|
|
},
|
|
"VPCIPRange": {
|
|
"Description": "The private IP address range for allocating IPs within the VPC.",
|
|
"Type": "String",
|
|
"MinLength": "9",
|
|
"MaxLength": "18",
|
|
"Default": "10.0.0.0/16",
|
|
"AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
|
|
"ConstraintDescription": "must be a valid IP CIDR range of the form `x.x.x.x/x`."
|
|
},
|
|
"EvergreenImageId": {
|
|
"Description": "AMI to use for the EC2 Evergreen instance",
|
|
"Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
|
|
"Type": "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>"
|
|
},
|
|
"AgentImageId": {
|
|
"Description": "AMI to use for the EC2 agent instances",
|
|
"Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
|
|
"Type": "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>"
|
|
}
|
|
},
|
|
"Resources": {
|
|
|
|
"EvergreenVPC": {
|
|
"Type": "AWS::EC2::VPC",
|
|
"Properties": {
|
|
"EnableDnsSupport": true,
|
|
"EnableDnsHostnames": true,
|
|
"CidrBlock": {"Ref": "VPCIPRange"},
|
|
"InstanceTenancy": "default",
|
|
"Tags": [
|
|
{ "Key": "Application", "Value": {"Ref": "AWS::StackId"}},
|
|
{ "Key": "Name", "Value" : "VPC for Jenkins"}
|
|
]
|
|
}
|
|
},
|
|
"EvergreenInternetGateway": {
|
|
"Type": "AWS::EC2::InternetGateway",
|
|
"Properties": {
|
|
"Tags": [
|
|
{ "Key": "Name", "Value" : {"Fn::Sub": "Jenkins ${AWS::StackName}"}}
|
|
]
|
|
}
|
|
},
|
|
"EvergreenGatewayAttachment": {
|
|
"Type": "AWS::EC2::VPCGatewayAttachment",
|
|
"Properties" : {
|
|
"VpcId" : { "Ref" : "EvergreenVPC" },
|
|
"InternetGatewayId": { "Ref" : "EvergreenInternetGateway" }
|
|
}
|
|
},
|
|
"EvergreenSubnet": {
|
|
"Type" : "AWS::EC2::Subnet",
|
|
"Properties": {
|
|
"AvailabilityZone" : { "Fn::Select" : [ "0", { "Fn::GetAZs" : "" } ] },
|
|
"VpcId": { "Ref" : "EvergreenVPC" },
|
|
"CidrBlock" : {"Ref": "VPCIPRange"},
|
|
"MapPublicIpOnLaunch": true,
|
|
"Tags": [
|
|
{ "Key": "Name", "Value" : {"Fn::Sub": "Subnet for Jenkins ${AWS::StackName}"}}
|
|
]
|
|
}
|
|
},
|
|
"EvergreenRouteTable": {
|
|
"Type": "AWS::EC2::RouteTable",
|
|
"Properties": {
|
|
"VpcId" : { "Ref" : "EvergreenVPC" },
|
|
"Tags": [
|
|
{ "Key": "Name", "Value" : {"Fn::Sub": "RouteTable for Jenkins ${AWS::StackName}"}}
|
|
]
|
|
}
|
|
},
|
|
"EvergreenInternetRoute": {
|
|
"Type": "AWS::EC2::Route",
|
|
"DependsOn": "EvergreenGatewayAttachment",
|
|
"Properties": {
|
|
"DestinationCidrBlock" : "0.0.0.0/0",
|
|
"GatewayId": { "Ref" : "EvergreenInternetGateway" },
|
|
"RouteTableId": { "Ref" : "EvergreenRouteTable" }
|
|
}
|
|
},
|
|
"EvergreenSubnetRouteTableAssociation": {
|
|
"Type": "AWS::EC2::SubnetRouteTableAssociation",
|
|
"Properties": {
|
|
"RouteTableId": { "Ref" : "EvergreenRouteTable" },
|
|
"SubnetId": { "Ref" : "EvergreenSubnet" }
|
|
}
|
|
},
|
|
"EvergreenSecurityGroup" : {
|
|
"Type" : "AWS::EC2::SecurityGroup",
|
|
"Properties" : {
|
|
"VpcId" : {"Ref" : "EvergreenVPC"},
|
|
"GroupDescription" : "allow all traffic",
|
|
"SecurityGroupIngress" : [{
|
|
"IpProtocol": "-1",
|
|
"FromPort" : -1,
|
|
"ToPort" : -1,
|
|
"CidrIp" : "0.0.0.0/0"
|
|
}],
|
|
"SecurityGroupEgress" : [{
|
|
"IpProtocol" : "-1",
|
|
"CidrIp" : "0.0.0.0/0"
|
|
}],
|
|
"Tags": [
|
|
{ "Key": "Name", "Value" : {"Fn::Sub": "Global SecurityGroup for ${AWS::StackName}"}}
|
|
]
|
|
}
|
|
},
|
|
|
|
"EC2EvergreenInstance": {
|
|
"Type": "AWS::EC2::Instance",
|
|
"Properties": {
|
|
"ImageId": {"Ref": "EvergreenImageId"},
|
|
"InstanceType": {"Ref": "InstanceTypeParameter"},
|
|
"IamInstanceProfile": {"Ref": "MasterInstanceProfile"},
|
|
"BlockDeviceMappings": [
|
|
{
|
|
"DeviceName": "/dev/xvda",
|
|
"Ebs": {
|
|
"VolumeSize": "115"
|
|
}
|
|
}
|
|
],
|
|
"KeyName" : { "Ref" : "KeyNameParameter" },
|
|
"SecurityGroupIds": [
|
|
{ "Ref": "EvergreenMasterSecurityGroup"}
|
|
],
|
|
"SubnetId": { "Ref" : "EvergreenSubnet" },
|
|
"Tags" : [
|
|
{"Key" : "Name", "Value" : "Jenkins Evergreen Master"}
|
|
],
|
|
"UserData": {
|
|
"Fn::Base64" : {
|
|
"Fn::Join" : ["", [
|
|
"#!/bin/bash -v\n",
|
|
"# Install Docker to be able to start the Jenkins Evergreen container\n",
|
|
"sudo yum update -y\n",
|
|
"sudo yum install -y docker\n",
|
|
"sudo service docker start\n",
|
|
"sudo usermod -a -G docker ec2-user # not strictly necessary\n",
|
|
"# Now the Evergreen specific part\n",
|
|
"export DOCKER_IMAGE=jenkins/evergreen:aws-ec2-cloud\n",
|
|
"echo \"", { "Ref": "PrivateKey"}, "\" > ssh-agents-private-key\n",
|
|
"sudo docker volume create jenkins-evergreen-data\n",
|
|
"sudo docker pull $DOCKER_IMAGE\n",
|
|
"sudo docker run -d -p 8080:80 -p 50000:50000 ",
|
|
" --name evergreen",
|
|
" --restart=always",
|
|
" -v jenkins-evergreen-data:/evergreen/data",
|
|
" -v $PWD/ssh-agents-private-key:/run/secrets/PRIVATE_KEY:ro",
|
|
" -e REGION=", {"Ref":"AWS::Region"},
|
|
" -e AGENT_AMI=", {"Ref":"AgentImageId"},
|
|
" -e ARTIFACT_MANAGER_S3_BUCKET_NAME=", {"Ref":"S3BucketForArtifactManager"},
|
|
" -e AGENT_SECURITY_GROUP=", {"Ref":"EvergreenAgentSecurityGroup"},
|
|
" -e AGENT_SUBNET=", {"Ref":"EvergreenSubnet"},
|
|
" $DOCKER_IMAGE\n"
|
|
]
|
|
]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"EC2EvergreenInstanceEIP": {
|
|
"DependsOn": [
|
|
"EvergreenVPC"
|
|
],
|
|
"Type": "AWS::EC2::EIP",
|
|
"Properties": {
|
|
"Domain": "vpc",
|
|
"InstanceId" : {
|
|
"Ref" : "EC2EvergreenInstance"
|
|
}
|
|
}
|
|
},
|
|
"EvergreenMasterSecurityGroup" : {
|
|
"Type" : "AWS::EC2::SecurityGroup",
|
|
"Properties" : {
|
|
"GroupDescription" : "Enable HTTP access via port 8080 and JNLP port (TODO: restrict agent port)",
|
|
"VpcId" : { "Ref":"EvergreenVPC"},
|
|
"SecurityGroupIngress" : [
|
|
{"IpProtocol" : "tcp", "FromPort" : 22, "ToPort" : 22, "CidrIp" : { "Ref" : "SSHLocation"}},
|
|
{"IpProtocol" : "tcp", "FromPort" : 8080, "ToPort" : 8080, "CidrIp" : "0.0.0.0/0"},
|
|
{"IpProtocol" : "tcp", "FromPort" : 50000, "ToPort" : 50000, "CidrIp" : "0.0.0.0/0"}
|
|
]
|
|
}
|
|
},
|
|
"EvergreenAgentSecurityGroup" : {
|
|
"Type" : "AWS::EC2::SecurityGroup",
|
|
"Properties" : {
|
|
"GroupDescription" : "Enable HTTP access via port 8080 and JNLP port (TODO: restrict agent port)",
|
|
"VpcId" : { "Ref":"EvergreenVPC"},
|
|
"SecurityGroupIngress" : [
|
|
{"IpProtocol" : "tcp", "FromPort" : 22, "ToPort" : 22, "CidrIp" : "0.0.0.0/0"}
|
|
]
|
|
}
|
|
},
|
|
"MasterInstanceProfile": {
|
|
"Type": "AWS::IAM::InstanceProfile",
|
|
"Properties": {
|
|
"Roles": [ { "Ref": "EvergreenMasterRole" } ]
|
|
}
|
|
},
|
|
"EvergreenMasterRole": {
|
|
"Type": "AWS::IAM::Role",
|
|
"Properties": {
|
|
"AssumeRolePolicyDocument": {
|
|
"Version" : "2012-10-17",
|
|
"Statement": [ {
|
|
"Effect": "Allow",
|
|
"Principal": {
|
|
"Service": [ "ec2.amazonaws.com" ]
|
|
},
|
|
"Action": [ "sts:AssumeRole" ]
|
|
} ]
|
|
},
|
|
"Policies": [{
|
|
"PolicyName": "EC2CloudPluginPolicy",
|
|
"PolicyDocument": {
|
|
"Version": "2012-10-17",
|
|
"Statement": [{
|
|
"Sid": "ControlEC2JenkinsAgents",
|
|
"Effect": "Allow",
|
|
"Action": [
|
|
"ec2:DescribeInstances",
|
|
"ec2:TerminateInstances",
|
|
"ec2:RequestSpotInstances",
|
|
"ec2:DeleteTags",
|
|
"ec2:CreateTags",
|
|
"ec2:DescribeRegions",
|
|
"ec2:RunInstances",
|
|
"ec2:DescribeSpotInstanceRequests",
|
|
"ec2:StopInstances",
|
|
"ec2:DescribeSecurityGroups",
|
|
"ec2:GetConsoleOutput",
|
|
"ec2:DescribeImages",
|
|
"ec2:CancelSpotInstanceRequests",
|
|
"ec2:StartInstances",
|
|
"ec2:DescribeAvailabilityZones",
|
|
"ec2:DescribeSubnets",
|
|
"ec2:DescribeKeyPairs"
|
|
],
|
|
"Resource": "*"
|
|
}]
|
|
}
|
|
}, {
|
|
"PolicyName": "S3ArtifactManagerPolicy",
|
|
"PolicyDocument": {
|
|
"Version": "2012-10-17",
|
|
"Statement": [
|
|
{
|
|
"Sid": "TodoRefineSecurityALot",
|
|
"Effect": "Allow",
|
|
"Action": [
|
|
"s3:PutObject",
|
|
"s3:GetObject",
|
|
"s3:ListBucket",
|
|
"s3:DeleteObject"
|
|
],
|
|
"Resource": "*"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"S3BucketForArtifactManager": {
|
|
"Type": "AWS::S3::Bucket"
|
|
},
|
|
"EC2EvergreenInstanceAlarm": {
|
|
"Type": "AWS::CloudWatch::Alarm",
|
|
"Properties": {
|
|
"AlarmDescription": "Trigger a recovery when instance status check fails for 5 consecutive minutes.",
|
|
"Namespace": "AWS/EC2",
|
|
"MetricName": "StatusCheckFailed_System",
|
|
"Statistic": "Minimum",
|
|
"Period": 60,
|
|
"EvaluationPeriods": 5,
|
|
"ComparisonOperator": "GreaterThanThreshold",
|
|
"Threshold": 0,
|
|
"AlarmActions": [ {"Fn::Join" : ["", ["arn:aws:automate:", { "Ref" : "AWS::Region" }, ":ec2:recover" ]]} ],
|
|
"Dimensions": [{"Name": "InstanceId","Value": {"Ref": "EC2EvergreenInstance"}}]
|
|
}
|
|
}
|
|
},
|
|
"Outputs": {
|
|
"EC2EvergreenInstanceIP": {
|
|
"Description": "Public IP address of the Evergreen EC2 instance",
|
|
"Value": {
|
|
"Fn::GetAtt": [
|
|
"EC2EvergreenInstance",
|
|
"PublicIp"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|