diff --git a/CloudFormation/README.md b/CloudFormation/README.md
new file mode 100644
index 0000000..5b85ff7
--- /dev/null
+++ b/CloudFormation/README.md
@@ -0,0 +1,71 @@
+# CloudFormation Template For Artifactory Enterprise
+
+### Steps to Deploy Artifactory Enterprise using CloudFormation template
+
+1. Go to AWS Console and Select CloudFormation. Then click on Create Stack.
+ You will see following window.
+
+
+2. Upload Artifactory-enterprise.json (Artifactory Enterprise template) and click next.
+
+
+3. Provide required information like stack name, DBAllocatedStorage, DBInstanceClass, DBName, DBPassword,
+ DBUser, InstanceType, InstanceStorage, MasterKey, ArtifactoryVersion, KeyName, ArtifactoryLicense1-5, MultiAZDatabase, SSHLocation, Certificate, CertificateKey, SecondaryNodeCount. Then click next.
+
+
+4. Mark on checkbox to allow CloudFormation to create IAM user for Artifactory to access S3 bucket.
+
+
+5. Once Stack in deployed you will see Artifactory Load Balancer URL in output as showed in screenshot.
+
+
+6. Open Artifactory URL and you will be able to see Artifactory UI.
+
+
+7. Let's make sure that Artifactory is running in High Availability mode. Go to Admin -> High Availability in Artifactory UI to see this table.
+
+
+8. Now let's add 2 more nodes to Artifactory Enterprise cluster. Go to CloudFormation UI in AWS console and select newly deployed Artifactory Enterprise Stack.
+ Click on Action -> Update Stack.
+
+
+9. Increase SecondaryNodeCount from 0 to 2. Then update the Stack.
+
+
+10. It will take few minutes to update stack.
+
+
+11. Once Stack is updated.
+
+
+12. You will be able to see 3 nodes in High Availability table in Artifactory UI as part of Enterprise cluster.
+
+
+### Note:
+1. This template only supports Artifactory version 5.8.x and above.
+2. Turn off daily backups. Read Documentation provided [here](https://www.jfrog.com/confluence/display/RTF/Managing+Backups)
+3. Use SSL Certificate with valid wild card to you artifactory as docker registry with subdomain method.
+
+### Steps to setup Artifactory as secure docker registry
+considering you have SSL certificate for `*.jfrog.team`
+1. Pass your SSL Certificate in parameter `Certificate` as string
+2. Pass your SSL Certificate Key in parameter `CertificateKey` as string
+3. Set `CertificateDomain` as `jfrog.team`
+4. Set `ArtifactoryServerName` as `artifactory` if you want to access artifactory with `https://artifactory.jfrog.team`
+5. Create Rout53 with entry `artifactory.jfrog.team` pointing to ELB value provided as output in CloudFormation Stack.
+6. Create Rout53 with entry `*.jfrog.team` pointing to ELB value provided as output in CloudFormation Stack.
+7. If you have virtual docker registry with name `docker-virtual` in artifactory. You can access it via `docker-virtual.jfrog.team`
+ e.g ```docker pull docker-virtual.jfrog.team/nginx```
+
+### Steps to upgrade Artifactory Version
+
+1. Go to AWS Console and Select CloudFormation Artifactory Stack you want to upgrade. Then click on Update Stack.
+
+2. Change Artifactory version in parameters from old version to version you want to deploy.
+ for e.g. 5.8.1 to 5.8.2
+
+ 
+
+3. You will see instances will get upgraded one by one. Depending on your cluster size it will take 20-30 minutes to update stack.
+
+
\ No newline at end of file
diff --git a/CloudFormation/artifactory-enterprise.json b/CloudFormation/artifactory-enterprise.json
new file mode 100644
index 0000000..a15ba84
--- /dev/null
+++ b/CloudFormation/artifactory-enterprise.json
@@ -0,0 +1,1343 @@
+{
+ "AWSTemplateFormatVersion" : "2010-09-09",
+
+ "Description" : "AWS CloudFormation Template to setup Artifactory Enterprise.",
+
+ "Parameters" : {
+
+ "InstanceType" : {
+ "Description" : "Artifactory EC2 instance type",
+ "Type" : "String",
+ "Default" : "m4.xlarge",
+ "AllowedValues" : [ "t1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m2.xlarge","m2.2xlarge","m2.4xlarge","m3.xlarge","m3.2xlarge", "m4.xlarge", "c1.medium","c1.xlarge","cc1.4xlarge","cc2.8xlarge","cg1.4xlarge"],
+ "ConstraintDescription" : "must be a valid EC2 instance type."
+ },
+
+ "ExtraJavaOptions":{
+ "Description": "Setting Java Memory Parameters for Artifactory",
+ "Default" : "-server -Xms2g -Xmx14g -Xss256k -XX:+UseG1GC -XX:OnOutOfMemoryError=\\\\\\\"kill -9 %p\\\\\\\"",
+ "Type" : "String"
+ },
+
+ "InstanceStorage":{
+ "Description": "Artifactory instances storage size in (Gb)",
+ "Type": "Number",
+ "Default" : "250",
+ "MinValue": "250",
+ "ConstraintDescription" : "must be more then 250 Gb."
+ },
+
+ "SecondaryNodeCount": {
+ "Description" : "Number of Artifactory Secondary instances to launch",
+ "Type" : "Number",
+ "Default" : "0",
+ "MinValue" : "0",
+ "MaxValue": "9"
+ },
+
+ "KeyName": {
+ "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
+ "Type": "AWS::EC2::KeyPair::KeyName",
+ "ConstraintDescription" : "must be the name of an existing EC2 KeyPair."
+ },
+
+ "MasterKey": {
+ "NoEcho": "true",
+ "Description" : "Master key for Artifactory cluster. Generate master.key using command '$openssl rand -hex 16'",
+ "Type": "String",
+ "MinLength": "1",
+ "MaxLength": "64",
+ "AllowedPattern" : "[a-zA-Z0-9][a-zA-Z0-9]*",
+ "Default": "1ce2be4490ca2c662cb79636cf9b7b8e"
+ },
+
+ "ArtifactoryVersion": {
+ "Description": "Artifactory version to deploy",
+ "Type": "String",
+ "Default": "5.8.1"
+ },
+
+ "ArtifactoryLicense1": {
+ "Description": "Artifactory Enterprise License. Providing one license is mandatory",
+ "Type": "String"
+ },
+
+ "ArtifactoryLicense2": {
+ "Description": "Artifactory Enterprise License",
+ "Type": "String"
+ },
+
+ "ArtifactoryLicense3": {
+ "Description": "Artifactory Enterprise License",
+ "Type": "String"
+ },
+
+ "ArtifactoryLicense4": {
+ "Description": "Artifactory Enterprise License",
+ "Type": "String"
+ },
+
+ "ArtifactoryLicense5": {
+ "Description": "Artifactory Enterprise License",
+ "Type": "String"
+ },
+
+ "Certificate": {
+ "Description": "To use Artifactory as docker registry you need to provide wild card valid Certificate. Provide your SSL Certificate.",
+ "Type": "String",
+ "Default": "-----BEGIN CERTIFICATE----- MIIFhzCCA2+gAwIBAgIJALC4r5BQWZE4MA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRMwEQYDVQQHDApTYW50YUNsYXJh MQswCQYDVQQKDAJJVDEUMBIGA1UEAwwLKi5sb2NhbGhvc3QwHhcNMTgwMTE3MTk0 NjI4WhcNMTkwMTA4MTk0NjI4WjBaMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2Fs aWZvcm5pYTETMBEGA1UEBwwKU2FudGFDbGFyYTELMAkGA1UECgwCSVQxFDASBgNV BAMMCyoubG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA 7KfOWDQlov8cMa8r/lcJqiWZaH9myQC74Vbe0HXsntQbcvljkjG2P7ebm5dd9Bzc sauNOJpbKf5AhFK1iwJUAkciGc1LR4k8wfWmQM3NPS8hrqrtH20zqNpdFRpNYjja JofwccPNm030GhhZkZ95TpruvmswMDwspl3jfqdcc/eiQsHcKyGnV2a+UAeoqe7J mHhmhRy1MLqAjF5U1GrUYUONA+22iRDJb4c9B91QoWvsnXpdA9NKV/mmA3/rIdx6 Ld2IPRdrIw2K5sAnXsh3bx2oCSvSfussf0x+4XDrnsaHVfjwvfNL8ECOuac2Oi/E WOp9528gOohpFAuwEt63Vl5p8/CC9m0HJDTZBKm2l5eD1kdPIj4PvP9Sn9CxGXKQ E1bxWoFxGX8EyRW0b0NK31N7b8JPZ1SoFNiB5amOMNLvR26a7cQrKumTuJeYK9Ja JaxhMXM7R0DA0Ev8ZG2xmyCygox+1KPSmJOIEpT70BFbj3rKLNqP22ET+zvPuh+2 DdgyrpHFeYkGWjMbWPjK7wJsD2zM8ccoJQfepPz8I4rT0JfrKAQgCGuGOggneaNJ KTVGNOFbj5AXdZ/Q+GvNommyRdq4J7EnqY6L+P25fo5qZ6UZ/iS0tPcvxgn0Fdhs pUPbQyQIDZyxZd3Q1lUIE38ol8P66mS2zbzf8EeOCoUCAwEAAaNQME4wHQYDVR0O BBYEFETAQM/5P7XJ8kevHFj6BPndQOFaMB8GA1UdIwQYMBaAFETAQM/5P7XJ8kev HFj6BPndQOFaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAJ1TepKv LWYhFmVQcgZwZf/qt1a1cohzJSm6da9RCnnAWC7WC/U117bgSomtrH1v0OysHFhB zBBUeBqI7+OmzAX8dhj+roKkcnFUM/IwlK1eueIIA//CWvEf/o0XExilVS2yCc9d PTpOQBXwk9QinxK36kHdBiGxa7dW0JPnOEEmuMgGORKeLy4J6Ik8iSeFY1SZVcOI +6WWvoKciPlmIeccC+6YVmkeBwhP2o5r5w/UAaO2hSnGvmm4UIj/VJv4VQu7xTUp cIfFz5NtIr80DbqcyPiEMS2ETJ4L/kO4MS5FfeEXyQuXCzmiIDVY6tE3C7+kZmK4 JzPLuWm9ndQoyQySOGfQqvlUR1+YxUdvmu3LrOS5dOA354Q36wHa4wEGUoHU/7GV fYQmmmDSDaNSpXW5PFey6scFyDBS/yYJ0H9EjYb/11HeWYj8Yv5xTWj8nhzJONC8 D6Y5ydlU4PifM2pOf88pTYpmogNwLJWXbql5I9cvMa8APo4yLVqcISU5ynsvFke+ Non+T0mHpJai/hrA9NK+s6EGC1dAX58jy61h6FhOPI1d4s/mov/KMa2t3SfZp5SF 81aR6dHvO56teiK5M1xMkrqG75zh3TMFJJLRFe9XxeB4JeN76URB3mgADOUqkBxd ibSgVqfKwOw4IujEcqMUc5mqSnbLY1Dv+oby -----END CERTIFICATE-----"
+ },
+
+ "CertificateKey": {
+ "Description": "Provide your SSL Certificate key",
+ "Type": "String",
+ "Default": "-----BEGIN PRIVATE KEY----- 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 S+j1+iUKGGhwVmhqh75q5do3+VF3XlAh -----END PRIVATE KEY-----"
+ },
+
+ "CertificateDomain":{
+ "Description": "Provide your Certificate Domain Name. For e.g jfrog.team for certificate with *.jfrog.team",
+ "Type": "String",
+ "Default": "artifactory"
+ },
+
+ "ArtifactoryServerName":{
+ "Description": "Provide artifactory server name to be used in Nginx. e.g artifactory for artifactory.jfrog.team",
+ "Type": "String",
+ "Default": "artifactory"
+ },
+
+ "DBName": {
+ "Default": "artdb",
+ "Description" : "MySQL database name",
+ "Type": "String",
+ "MinLength": "1",
+ "MaxLength": "64",
+ "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
+ "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
+ },
+
+ "DBUser": {
+ "NoEcho": "true",
+ "Default": "artifactory",
+ "Description" : "Username for MySQL database access",
+ "Type": "String",
+ "MinLength": "1",
+ "MaxLength": "16",
+ "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
+ "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
+ },
+
+ "DBPassword": {
+ "NoEcho": "true",
+ "Default": "password",
+ "Description" : "Password for MySQL database access",
+ "Type": "String",
+ "MinLength": "8",
+ "MaxLength": "41",
+ "AllowedPattern" : "[a-zA-Z0-9]*",
+ "ConstraintDescription" : "must contain only alphanumeric characters."
+ },
+
+ "DBAllocatedStorage": {
+ "Default": "5",
+ "Description" : "The size of the database (Gb)",
+ "Type": "Number",
+ "MinValue": "5",
+ "MaxValue": "1024",
+ "ConstraintDescription" : "must be between 5 and 1024Gb."
+ },
+
+ "DBInstanceClass": {
+ "Description" : "The database instance type",
+ "Type": "String",
+ "Default": "db.t2.small",
+ "AllowedValues" : [ "db.t1.micro", "db.m1.small", "db.m1.medium", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge", "db.m3.medium", "db.m3.large", "db.m3.xlarge", "db.m3.2xlarge", "db.m4.large", "db.m4.xlarge", "db.m4.2xlarge", "db.m4.4xlarge", "db.m4.10xlarge", "db.r3.large", "db.r3.xlarge", "db.r3.2xlarge", "db.r3.4xlarge", "db.r3.8xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge", "db.cr1.8xlarge", "db.t2.micro", "db.t2.small", "db.t2.medium", "db.t2.large"],
+ "ConstraintDescription" : "must select a valid database instance type."
+ },
+
+ "MultiAZDatabase": {
+ "Default": "false",
+ "Description" : "Create a Multi-AZ MySQL Amazon RDS database instance",
+ "Type": "String",
+ "AllowedValues" : [ "true", "false" ],
+ "ConstraintDescription" : "must be either true or false."
+ },
+
+ "SSHLocation" : {
+ "Description" : " The IP address range that can be used to SSH to the EC2 instances",
+ "Type": "String",
+ "MinLength": "9",
+ "MaxLength": "18",
+ "Default": "0.0.0.0/0",
+ "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."
+ }
+ },
+
+ "Mappings" : {
+ "AWSInstanceType2Arch" : {
+ "t1.micro" : { "Arch" : "PV64" },
+ "t2.nano" : { "Arch" : "HVM64" },
+ "t2.micro" : { "Arch" : "HVM64" },
+ "t2.small" : { "Arch" : "HVM64" },
+ "t2.medium" : { "Arch" : "HVM64" },
+ "t2.large" : { "Arch" : "HVM64" },
+ "m1.small" : { "Arch" : "PV64" },
+ "m1.medium" : { "Arch" : "PV64" },
+ "m1.large" : { "Arch" : "PV64" },
+ "m1.xlarge" : { "Arch" : "PV64" },
+ "m2.xlarge" : { "Arch" : "PV64" },
+ "m2.2xlarge" : { "Arch" : "PV64" },
+ "m2.4xlarge" : { "Arch" : "PV64" },
+ "m3.medium" : { "Arch" : "HVM64" },
+ "m3.large" : { "Arch" : "HVM64" },
+ "m3.xlarge" : { "Arch" : "HVM64" },
+ "m3.2xlarge" : { "Arch" : "HVM64" },
+ "m4.large" : { "Arch" : "HVM64" },
+ "m4.xlarge" : { "Arch" : "HVM64" },
+ "m4.2xlarge" : { "Arch" : "HVM64" },
+ "m4.4xlarge" : { "Arch" : "HVM64" },
+ "m4.10xlarge" : { "Arch" : "HVM64" },
+ "c1.medium" : { "Arch" : "PV64" },
+ "c1.xlarge" : { "Arch" : "PV64" },
+ "c3.large" : { "Arch" : "HVM64" },
+ "c3.xlarge" : { "Arch" : "HVM64" },
+ "c3.2xlarge" : { "Arch" : "HVM64" },
+ "c3.4xlarge" : { "Arch" : "HVM64" },
+ "c3.8xlarge" : { "Arch" : "HVM64" },
+ "c4.large" : { "Arch" : "HVM64" },
+ "c4.xlarge" : { "Arch" : "HVM64" },
+ "c4.2xlarge" : { "Arch" : "HVM64" },
+ "c4.4xlarge" : { "Arch" : "HVM64" },
+ "c4.8xlarge" : { "Arch" : "HVM64" },
+ "g2.2xlarge" : { "Arch" : "HVMG2" },
+ "g2.8xlarge" : { "Arch" : "HVMG2" },
+ "r3.large" : { "Arch" : "HVM64" },
+ "r3.xlarge" : { "Arch" : "HVM64" },
+ "r3.2xlarge" : { "Arch" : "HVM64" },
+ "r3.4xlarge" : { "Arch" : "HVM64" },
+ "r3.8xlarge" : { "Arch" : "HVM64" },
+ "i2.xlarge" : { "Arch" : "HVM64" },
+ "i2.2xlarge" : { "Arch" : "HVM64" },
+ "i2.4xlarge" : { "Arch" : "HVM64" },
+ "i2.8xlarge" : { "Arch" : "HVM64" },
+ "d2.xlarge" : { "Arch" : "HVM64" },
+ "d2.2xlarge" : { "Arch" : "HVM64" },
+ "d2.4xlarge" : { "Arch" : "HVM64" },
+ "d2.8xlarge" : { "Arch" : "HVM64" },
+ "hi1.4xlarge" : { "Arch" : "HVM64" },
+ "hs1.8xlarge" : { "Arch" : "HVM64" },
+ "cr1.8xlarge" : { "Arch" : "HVM64" },
+ "cc2.8xlarge" : { "Arch" : "HVM64" }
+ },
+
+ "AWSRegionArch2AMI" : {
+ "us-east-1" : {"PV64" : "ami-2a69aa47", "HVM64" : "ami-6869aa05", "HVMG2" : "ami-61e27177"},
+ "us-west-2" : {"PV64" : "ami-7f77b31f", "HVM64" : "ami-7172b611", "HVMG2" : "ami-60aa3700"},
+ "us-west-1" : {"PV64" : "ami-a2490dc2", "HVM64" : "ami-31490d51", "HVMG2" : "ami-4b694d2b"},
+ "eu-west-1" : {"PV64" : "ami-4cdd453f", "HVM64" : "ami-f9dd458a", "HVMG2" : "ami-2955524f"},
+ "eu-west-2" : {"PV64" : "NOT_SUPPORTED", "HVM64" : "ami-886369ec", "HVMG2" : "NOT_SUPPORTED"},
+ "eu-central-1" : {"PV64" : "ami-6527cf0a", "HVM64" : "ami-ea26ce85", "HVMG2" : "ami-81ac71ee"},
+ "ap-northeast-1" : {"PV64" : "ami-3e42b65f", "HVM64" : "ami-374db956", "HVMG2" : "ami-46220c21"},
+ "ap-northeast-2" : {"PV64" : "NOT_SUPPORTED", "HVM64" : "ami-2b408b45", "HVMG2" : "NOT_SUPPORTED"},
+ "ap-southeast-1" : {"PV64" : "ami-df9e4cbc", "HVM64" : "ami-a59b49c6", "HVMG2" : "ami-c212aba1"},
+ "ap-southeast-2" : {"PV64" : "ami-63351d00", "HVM64" : "ami-dc361ebf", "HVMG2" : "ami-0ad2db69"},
+ "ap-south-1" : {"PV64" : "NOT_SUPPORTED", "HVM64" : "ami-ffbdd790", "HVMG2" : "ami-ca3042a5"},
+ "us-east-2" : {"PV64" : "NOT_SUPPORTED", "HVM64" : "ami-f6035893", "HVMG2" : "NOT_SUPPORTED"},
+ "ca-central-1" : {"PV64" : "NOT_SUPPORTED", "HVM64" : "ami-730ebd17", "HVMG2" : "NOT_SUPPORTED"},
+ "sa-east-1" : {"PV64" : "ami-1ad34676", "HVM64" : "ami-6dd04501", "HVMG2" : "NOT_SUPPORTED"},
+ "cn-north-1" : {"PV64" : "ami-77559f1a", "HVM64" : "ami-8e6aa0e3", "HVMG2" : "NOT_SUPPORTED"}
+ }
+ },
+
+ "Resources" : {
+
+ "IAMUser": {
+ "Type": "AWS::IAM::User"
+ },
+
+ "IAMAcessKey": {
+ "Type": "AWS::IAM::AccessKey",
+ "Properties": { "UserName": { "Ref": "IAMUser" } }
+ },
+
+ "S3Bucket" : {
+ "Type": "AWS::S3::Bucket",
+ "Properties": { "AccessControl": "Private"}
+ },
+
+ "IAMPolicy": {
+ "Type": "AWS::IAM::Policy",
+ "Properties": {
+ "PolicyName": "S3BucketPermissions",
+ "PolicyDocument" : {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "S3BucketPermissions",
+ "Effect": "Allow",
+ "Action": ["s3:*"],
+ "Resource": [
+ { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3Bucket" } ] ] },
+ { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3Bucket" }, "/*" ] ] }
+ ]
+ }
+ ]
+ },
+ "Users": [ { "Ref": "IAMUser" } ]
+ }
+ },
+
+ "VPC" : {
+ "Type" : "AWS::EC2::VPC",
+ "Properties" : {
+ "CidrBlock" : "10.0.0.0/16",
+ "Tags" : [
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
+ {"Key" : "Network", "Value" : "Public" }
+ ]
+ }
+ },
+
+ "PublicSubnet1" : {
+ "Type" : "AWS::EC2::Subnet",
+ "Properties" : {
+ "VpcId" : { "Ref" : "VPC" },
+ "CidrBlock" : "10.0.1.0/24",
+ "MapPublicIpOnLaunch" :"true",
+ "AvailabilityZone" : {
+ "Fn::Select" : [ "0", { "Fn::GetAZs" : "" } ]
+ },
+ "Tags" : [
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
+ {"Key" : "Network", "Value" : "Public" }
+ ]
+ }
+ },
+
+ "PublicSubnet2" : {
+ "Type" : "AWS::EC2::Subnet",
+ "Properties" : {
+ "VpcId" : { "Ref" : "VPC" },
+ "CidrBlock" : "10.0.2.0/24",
+ "MapPublicIpOnLaunch" :"true",
+ "AvailabilityZone" : {
+ "Fn::Select" : [ "1", { "Fn::GetAZs" : "" } ]
+ },
+ "Tags" : [
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
+ {"Key" : "Network", "Value" : "Public" }
+ ]
+ }
+ },
+
+ "InternetGateway" : {
+ "Type" : "AWS::EC2::InternetGateway",
+ "Properties" : {
+ "Tags" : [
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
+ {"Key" : "Network", "Value" : "Public" }
+ ]
+ }
+ },
+
+ "AttachGateway" : {
+ "Type" : "AWS::EC2::VPCGatewayAttachment",
+ "Properties" : {
+ "VpcId" : { "Ref" : "VPC" },
+ "InternetGatewayId" : { "Ref" : "InternetGateway" }
+ }
+ },
+
+ "PublicRouteTable" : {
+ "Type" : "AWS::EC2::RouteTable",
+ "Properties" : {
+ "VpcId" : {"Ref" : "VPC"},
+ "Tags" : [
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
+ {"Key" : "Network", "Value" : "Public" }
+ ]
+ }
+ },
+
+ "PublicRoute" : {
+ "Type" : "AWS::EC2::Route",
+ "DependsOn" : "AttachGateway",
+ "Properties" : {
+ "RouteTableId" : { "Ref" : "PublicRouteTable" },
+ "DestinationCidrBlock" : "0.0.0.0/0",
+ "GatewayId" : { "Ref" : "InternetGateway" }
+ }
+ },
+
+ "PublicSubnetRouteTableAssociation1" : {
+ "Type" : "AWS::EC2::SubnetRouteTableAssociation",
+ "Properties" : {
+ "SubnetId" : { "Ref" : "PublicSubnet1" },
+ "RouteTableId" : { "Ref" : "PublicRouteTable" }
+ }
+ },
+
+ "PublicSubnetRouteTableAssociation2" : {
+ "Type" : "AWS::EC2::SubnetRouteTableAssociation",
+ "Properties" : {
+ "SubnetId" : { "Ref" : "PublicSubnet2" },
+ "RouteTableId" : { "Ref" : "PublicRouteTable" }
+ }
+ },
+
+
+ "PublicNetworkAcl" : {
+ "Type" : "AWS::EC2::NetworkAcl",
+ "Properties" : {
+ "VpcId" : {"Ref" : "VPC"},
+ "Tags" : [
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
+ {"Key" : "Network", "Value" : "Public" }
+ ]
+ }
+ },
+
+ "InboundHTTPPublicNetworkAclEntry" : {
+ "Type" : "AWS::EC2::NetworkAclEntry",
+ "Properties" : {
+ "NetworkAclId" : {"Ref" : "PublicNetworkAcl"},
+ "RuleNumber" : "100",
+ "Protocol" : "6",
+ "RuleAction" : "allow",
+ "Egress" : "false",
+ "CidrBlock" : "0.0.0.0/0",
+ "PortRange" : {"From" : "0", "To" : "65535"}
+ }
+ },
+
+ "InboundDynamicPortsPublicNetworkAclEntry" : {
+ "Type" : "AWS::EC2::NetworkAclEntry",
+ "Properties" : {
+ "NetworkAclId" : {"Ref" : "PublicNetworkAcl"},
+ "RuleNumber" : "101",
+ "Protocol" : "6",
+ "RuleAction" : "allow",
+ "Egress" : "false",
+ "CidrBlock" : "0.0.0.0/0",
+ "PortRange" : {"From" : "0", "To" : "65535"}
+ }
+ },
+
+ "OutboundHTTPPublicNetworkAclEntry" : {
+ "Type" : "AWS::EC2::NetworkAclEntry",
+ "Properties" : {
+ "NetworkAclId" : {"Ref" : "PublicNetworkAcl"},
+ "RuleNumber" : "100",
+ "Protocol" : "6",
+ "RuleAction" : "allow",
+ "Egress" : "true",
+ "CidrBlock" : "0.0.0.0/0",
+ "PortRange" : {"From" : "0", "To" : "65535"}
+ }
+ },
+
+ "OutBoundDynamicPortPublicNetworkAclEntry" : {
+ "Type" : "AWS::EC2::NetworkAclEntry",
+ "Properties" : {
+ "NetworkAclId" : {"Ref" : "PublicNetworkAcl"},
+ "RuleNumber" : "101",
+ "Protocol" : "6",
+ "RuleAction" : "allow",
+ "Egress" : "true",
+ "CidrBlock" : "0.0.0.0/0",
+ "PortRange" : {"From" : "0", "To" : "65535"}
+ }
+ },
+
+ "PublicSubnetNetworkAclAssociation1" : {
+ "Type" : "AWS::EC2::SubnetNetworkAclAssociation",
+ "Properties" : {
+ "SubnetId" : { "Ref" : "PublicSubnet1" },
+ "NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
+ }
+ },
+
+ "PublicSubnetNetworkAclAssociation2" : {
+ "Type" : "AWS::EC2::SubnetNetworkAclAssociation",
+ "Properties" : {
+ "SubnetId" : { "Ref" : "PublicSubnet2" },
+ "NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
+ }
+ },
+
+ "PrivateSubnet" : {
+ "Type" : "AWS::EC2::Subnet",
+ "Properties" : {
+ "VpcId" : { "Ref" : "VPC" },
+ "CidrBlock" : "10.0.3.0/24",
+ "AvailabilityZone" : {
+ "Fn::Select" : [ "1", { "Fn::GetAZs" : "" } ]
+ },
+ "Tags" : [
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
+ {"Key" : "Network", "Value" : "Private" }
+ ]
+ }
+ },
+
+ "PrivateRouteTable" : {
+ "Type" : "AWS::EC2::RouteTable",
+ "Properties" : {
+ "VpcId" : {"Ref" : "VPC"},
+ "Tags" : [
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
+ {"Key" : "Network", "Value" : "Private" }
+ ]
+ }
+ },
+
+ "PrivateSubnetRouteTableAssociation" : {
+ "Type" : "AWS::EC2::SubnetRouteTableAssociation",
+ "Properties" : {
+ "SubnetId" : { "Ref" : "PrivateSubnet" },
+ "RouteTableId" : { "Ref" : "PrivateRouteTable" }
+ }
+ },
+
+ "PrivateNetworkAcl" : {
+ "Type" : "AWS::EC2::NetworkAcl",
+ "Properties" : {
+ "VpcId" : {"Ref" : "VPC"},
+ "Tags" : [
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
+ {"Key" : "Network", "Value" : "Private" }
+ ]
+ }
+ },
+
+ "InboundPrivateNetworkAclEntry" : {
+ "Type" : "AWS::EC2::NetworkAclEntry",
+ "Properties" : {
+ "NetworkAclId" : {"Ref" : "PrivateNetworkAcl"},
+ "RuleNumber" : "100",
+ "Protocol" : "6",
+ "RuleAction" : "allow",
+ "Egress" : "false",
+ "CidrBlock" : "0.0.0.0/0",
+ "PortRange" : {"From" : "0", "To" : "65535"}
+ }
+ },
+
+ "OutBoundPrivateNetworkAclEntry" : {
+ "Type" : "AWS::EC2::NetworkAclEntry",
+ "Properties" : {
+ "NetworkAclId" : {"Ref" : "PrivateNetworkAcl"},
+ "RuleNumber" : "100",
+ "Protocol" : "6",
+ "RuleAction" : "allow",
+ "Egress" : "true",
+ "CidrBlock" : "0.0.0.0/0",
+ "PortRange" : {"From" : "0", "To" : "65535"}
+ }
+ },
+
+ "PrivateSubnetNetworkAclAssociation" : {
+ "Type" : "AWS::EC2::SubnetNetworkAclAssociation",
+ "Properties" : {
+ "SubnetId" : { "Ref" : "PrivateSubnet" },
+ "NetworkAclId" : { "Ref" : "PrivateNetworkAcl" }
+ }
+ },
+
+ "ElasticLoadBalancer" : {
+ "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
+ "Properties" : {
+ "SecurityGroups" : [ { "Ref" : "ArtifactorySecurityGroup" } ],
+ "Subnets" : [ { "Ref" : "PublicSubnet1" }, { "Ref" : "PublicSubnet2" } ],
+ "AppCookieStickinessPolicy" :
+ [ {
+ "PolicyName" : "HTTPSCookieStickinessPolicy",
+ "CookieName" : "connect.sid"
+ } ],
+ "Listeners" : [ {
+ "LoadBalancerPort" : "80",
+ "InstancePort" : "80",
+ "InstanceProtocol": "HTTP",
+ "Protocol" : "HTTP"
+ },
+ {
+ "Protocol": "TCP",
+ "InstanceProtocol": "TCP",
+ "LoadBalancerPort": "443",
+ "InstancePort": "443"
+ } ],
+ "HealthCheck" : {
+ "Target" : { "Fn::Join" : [ "", ["HTTP:80/artifactory/webapp/#/login"]]},
+ "HealthyThreshold" : "3",
+ "UnhealthyThreshold" : "3",
+ "Interval" : "30",
+ "Timeout" : "15"
+ }
+ }
+ },
+
+ "PrimaryGroup" : {
+ "Type" : "AWS::AutoScaling::AutoScalingGroup",
+ "Properties" : {
+ "AvailabilityZones" : [{ "Fn::GetAtt" : [ "PublicSubnet1", "AvailabilityZone" ] },{ "Fn::GetAtt" : [ "PublicSubnet2", "AvailabilityZone" ] }],
+ "VPCZoneIdentifier" : [{ "Ref" : "PublicSubnet1" }, { "Ref" : "PublicSubnet2" }],
+ "LaunchConfigurationName" : { "Ref" : "PrimaryLaunchConfig" },
+ "MinSize" : "1",
+ "MaxSize" : "2",
+ "DesiredCapacity" : "1",
+ "LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancer" } ],
+ "HealthCheckGracePeriod" : "480",
+ "HealthCheckType" : "ELB"
+ },
+ "UpdatePolicy": {
+ "AutoScalingRollingUpdate": {
+ "MinInstancesInService": "0",
+ "MaxBatchSize": "1",
+ "PauseTime": "PT7M"
+ }
+ }
+ },
+
+ "PrimaryLaunchConfig": {
+ "Type" : "AWS::AutoScaling::LaunchConfiguration",
+ "Metadata" : {
+ "Comment1" : "Configure the bootstrap helpers to install the Artifactory Server",
+
+ "AWS::CloudFormation::Init" : {
+ "config" : {
+ "packages" : {
+ "yum" : {
+ "wget" : [],
+ "curl" : []
+ }
+ },
+
+ "files" : {
+
+ "/etc/nginx/nginx.conf" : {
+ "content" : { "Fn::Join" : ["", [
+ "#user nobody;\n",
+ "worker_processes 1;\n",
+ "error_log /var/log/nginx/error.log info;\n",
+ "#pid logs/nginx.pid;\n",
+ "events {\n",
+ " worker_connections 1024;\n",
+ "}\n",
+ "http {\n",
+ " include mime.types;\n",
+ " include /etc/nginx/conf.d/*.conf;\n",
+ " default_type application/octet-stream;\n",
+ " log_format main '$remote_addr - $remote_user [$time_local] \"$request\" '\n",
+ "'$status $body_bytes_sent \"$http_referer\" '\n",
+ "'\"$http_user_agent\" \"$http_x_forwarded_for\"';\n",
+ " access_log /var/log/nginx/access.log main;\n",
+ " sendfile on;\n",
+ " #tcp_nopush on;\n",
+ " #keepalive_timeout 0;\n",
+ " keepalive_timeout 65;\n",
+ "}\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/db.properties" : {
+ "content" : { "Fn::Join" : ["", [
+ "type=mysql\n",
+ "driver=com.mysql.jdbc.Driver\n",
+ "url=jdbc:mysql://", {"Fn::GetAtt" : ["MySQLDatabase", "Endpoint.Address"]},":3306/", { "Ref" : "DBName" },"?characterEncoding=UTF-8&elideSetAutoCommits=true\n",
+ "username=", {"Ref" : "DBUser"}, "\n",
+ "password=", {"Ref" : "DBPassword"}, "\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/binarystore.xml" : {
+ "content" : { "Fn::Join" : ["", [
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "crossNetworkStrategy\n",
+ "crossNetworkStrategy\n",
+ "2\n",
+ "1\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ " remote\n",
+ "\n",
+ "\n",
+ "\n",
+ " local\n",
+ "\n",
+ "\n",
+ "\n",
+ "",{ "Fn::Join": [ "", [ "s3.dualstack.", { "Ref": "AWS::Region" }, ".amazonaws.com" ] ] },"\n",
+ "", {"Ref" : "IAMAcessKey"}, "\n",
+ "", { "Fn::GetAtt": [ "IAMAcessKey", "SecretAccessKey" ] }, "\n",
+ "", { "Ref": "S3Bucket" }, "\n",
+ "\n",
+ "\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/ha-node.properties" : {
+ "content" : { "Fn::Join" : ["", [
+ "node.id=art1\n",
+ "artifactory.ha.data.dir=/var/opt/jfrog/artifactory/data\n",
+ "context.url=http://127.0.0.1:8081/artifactory\n",
+ "membership.port=10001\n",
+ "hazelcast.interface=172.25.0.3\n",
+ "primary=true\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/security/master.key" : {
+ "content" : { "Fn::Join" : ["", [
+ {"Ref" : "MasterKey"}
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/etc/pki/tls/certs/result.pem" : {
+ "content" : { "Fn::Join" : ["", [
+ {"Ref" : "Certificate"}
+ ]]},
+ "mode" : "000777",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/etc/pki/tls/private/result.key" : {
+ "content" : { "Fn::Join" : ["", [
+ {"Ref" : "CertificateKey"}
+ ]]},
+ "mode" : "000777",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/plugins/inactiveServerCleaner.groovy" : {
+ "content" : { "Fn::Join" : ["", [
+ "import org.artifactory.state.ArtifactoryServerState\n",
+ "import org.artifactory.storage.db.servers.service.ArtifactoryServersCommonService\n",
+ "import org.artifactory.common.ConstantValues\n",
+ "import org.slf4j.Logger\n",
+ "import java.util.concurrent.TimeUnit\n",
+
+ "jobs {\n",
+ " clean(cron: \"0 0/1 * * * ?\") {\n",
+ " def artifactoryServersCommonService = ctx.beanForType(ArtifactoryServersCommonService)\n",
+ " def artifactoryInactiveServerCleaner = new ArtifactoryInactiveServersCleaner(artifactoryServersCommonService, log)\n",
+ " artifactoryInactiveServerCleaner.cleanInactiveArtifactoryServers()\n",
+ " }\n",
+ "}\n",
+
+ "public class ArtifactoryInactiveServersCleaner {\n",
+
+ " private ArtifactoryServersCommonService artifactoryServersCommonService\n",
+ " private Logger log\n",
+
+ " ArtifactoryInactiveServersCleaner(ArtifactoryServersCommonService artifactoryServersCommonService, Logger log) {\n",
+ " this.artifactoryServersCommonService = artifactoryServersCommonService\n",
+ " this.log = log\n",
+ " }\n",
+
+ " def cleanInactiveArtifactoryServers() {\n",
+ " List allMembers = artifactoryServersCommonService.getAllArtifactoryServers()\n",
+ " for (member in allMembers) {\n",
+ " def heartbeat = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - member.getLastHeartbeat())\n",
+ " def noheartbeat = heartbeat > ConstantValues.haHeartbeatStaleIntervalSecs.getInt()\n",
+ " if (member.getServerState() == ArtifactoryServerState.UNAVAILABLE || noheartbeat) {\n",
+ " log.info \"Running inactive artifactory servers cleaning task, found ${member.serverId} inactive servers to remove\"\n",
+ " artifactoryServersCommonService.removeServer(member.serverId)\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n"
+ ]]},
+ "mode" : "000777",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/artifactory.cluster.license" : {
+ "content" : { "Fn::Join" : ["", [
+ "", { "Ref" : "ArtifactoryLicense1" }, "\n",
+ "\n",
+ "", { "Ref" : "ArtifactoryLicense2" }, "\n",
+ "\n",
+ "", { "Ref" : "ArtifactoryLicense3" }, "\n",
+ "\n",
+ "", { "Ref" : "ArtifactoryLicense4" }, "\n",
+ "\n",
+ "", { "Ref" : "ArtifactoryLicense5" }, "\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/etc/nginx/conf.d/artifactory.conf" : {
+ "content" : { "Fn::Join" : ["", [
+ "ssl_certificate /etc/pki/tls/certs/cert.pem;\n",
+ "ssl_certificate_key /etc/pki/tls/private/cert.key;\n",
+ "ssl_session_cache shared:SSL:1m;\n",
+ "ssl_prefer_server_ciphers on;\n",
+ "## server configuration\n",
+ "server {\n",
+ " listen 443 ssl;\n",
+ " listen 80 ;\n",
+ " server_name ",{ "Ref" : "ArtifactoryServerName" },".",{ "Ref" : "CertificateDomain" }," ~(?.+)\\.",{ "Ref" : "CertificateDomain" },";\n",
+ " if ($http_x_forwarded_proto = '') {\n",
+ " set $http_x_forwarded_proto $scheme;\n",
+ " }\n",
+ " ## Application specific logs\n",
+ " ## access_log /var/log/nginx/artifactory-access.log timing;\n",
+ " ## error_log /var/log/nginx/artifactory-error.log;\n",
+ " rewrite ^/$ /artifactory/webapp/ redirect;\n",
+ " rewrite ^/artifactory/?(/webapp)?$ /artifactory/webapp/ redirect;\n",
+ " rewrite ^/(v1|v2)/(.*) /artifactory/api/docker/$repo/$1/$2;\n",
+ " chunked_transfer_encoding on;\n",
+ " client_max_body_size 0;\n",
+ " location /artifactory/ {\n",
+ " proxy_read_timeout 900;\n",
+ " proxy_pass_header Server;\n",
+ " proxy_cookie_path ~*^/.* /;\n",
+ " proxy_pass http://127.0.0.1:8081/artifactory/;\n",
+ " proxy_set_header X-Artifactory-Override-Base-Url $http_x_forwarded_proto://$host:$server_port/artifactory;\n",
+ " proxy_set_header X-Forwarded-Port $server_port;\n",
+ " proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;\n",
+ " proxy_set_header Host $http_host;\n",
+ " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n",
+ " }\n",
+ "}\n",
+ "\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/etc/cfn/cfn-hup.conf" : {
+ "content" : { "Fn::Join" : ["", [
+ "[main]\n",
+ "stack=", { "Ref" : "AWS::StackId" }, "\n",
+ "region=", { "Ref" : "AWS::Region" }, "\n"
+ ]]},
+ "mode" : "000400",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/etc/cfn/hooks.d/cfn-auto-reloader.conf" : {
+ "content": { "Fn::Join" : ["", [
+ "[cfn-auto-reloader-hook]\n",
+ "triggers=post.update\n",
+ "path=Resources.PrimaryLaunchConfig.Metadata.AWS::CloudFormation::Init\n",
+ "action=/opt/aws/bin/cfn-init -v ",
+ " --stack ", { "Ref" : "AWS::StackName" },
+ " --resource PrimaryLaunchConfig ",
+ " --region ", { "Ref" : "AWS::Region" }, "\n",
+ "runas=root\n"
+ ]]}
+ }
+ },
+
+ "commands" : {
+ "set_artifactory_node_id" : {
+ "command" : { "Fn::Join" : ["", ["sed -i -e \"s/art1/art-$(date +%s$RANDOM)/\" /var/opt/jfrog/artifactory/etc/ha-node.properties"]]}
+ },
+ "set_artifactory_context" : {
+ "command" : { "Fn::Join" : ["", ["sed -i -e \"s/127.0.0.1/$(curl http://169.254.169.254/latest/meta-data/public-ipv4)/\" /var/opt/jfrog/artifactory/etc/ha-node.properties"]]}
+ },
+ "set_hazelcast_interface" : {
+ "command" : { "Fn::Join" : ["", ["sed -i -e \"s/172.25.0.3/$(curl http://169.254.169.254/latest/meta-data/local-ipv4)/\" /var/opt/jfrog/artifactory/etc/ha-node.properties"]]}
+ },
+ "allow_ping_anonymous" : {
+ "command" : { "Fn::Join" : ["", ["echo \"artifactory.ping.allowUnauthenticated=true\" >> /var/opt/jfrog/artifactory/etc/artifactory.system.properties"]]}
+ },
+ "set_extra_java_options" : {
+ "command" : { "Fn::Join" : ["", ["echo \"export JAVA_OPTIONS=", "\\\"", { "Ref" : "ExtraJavaOptions" }, "\\\"", "\" >> /var/opt/jfrog/artifactory/etc/default"]]}
+ },
+ "set_permissions" : {
+ "command" : { "Fn::Join" : ["", ["chown artifactory:artifactory -R /var/opt/jfrog/artifactory/etc/* && chown artifactory:artifactory -R /var/opt/jfrog/artifactory/* && chown artifactory:artifactory -R /var/opt/jfrog/artifactory/etc/security"]]}
+ },
+ "generate_self_signed_cert" : {
+ "command" : { "Fn::Join" : ["", ["openssl req -nodes -x509 -newkey rsa:4096 -keyout /etc/pki/tls/private/example.key -out /etc/pki/tls/certs/example.pem -days 356 -subj \"/C=US/ST=California/L=SantaClara/O=IT/CN=*.localhost\""]]}
+ },
+ "format_ssl_certificate" : {
+ "command" : { "Fn::Join" : ["", ["cat /etc/pki/tls/certs/result.pem | sed 's/CERTIFICATE----- /CERTIFICATE-----\\n/g' | sed 's/-----END/\\n-----END/' > temp.pem | mv -f temp.pem /etc/pki/tls/certs/cert.pem"]]}
+ },
+ "format_ssl_certificate_key" : {
+ "command" : { "Fn::Join" : ["", ["cat /etc/pki/tls/private/result.key | sed 's/KEY----- /KEY-----\\n/g' | sed 's/-----END/\\n-----END/' > temp.key | mv -f temp.key /etc/pki/tls/private/cert.key"]]}
+ }
+ },
+
+ "services" : {
+ "sysvinit" : {
+ "artifactory" : { "enabled" : "true", "ensureRunning" : "true" },
+ "nginx" : { "enabled" : "true", "ensureRunning" : "true"},
+ "cfn-hup" : { "enabled" : "true", "ensureRunning" : "true",
+ "files" : ["/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf"]}
+ }
+ }
+ }
+ }
+ },
+ "Properties": {
+ "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
+ { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
+ "InstanceType" : { "Ref" : "InstanceType" },
+ "SecurityGroups" : [ {"Ref" : "ArtifactorySecurityGroup"} ],
+ "KeyName" : { "Ref" : "KeyName" },
+ "BlockDeviceMappings" : [
+ {
+ "DeviceName" : "/dev/xvda",
+ "Ebs" : { "VolumeSize" : { "Ref" : "InstanceStorage" }, "VolumeType" : "gp2", "DeleteOnTermination" : "true"}
+ }
+ ],
+ "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
+ "#!/bin/bash -xe\n",
+ "yum update -y aws-cfn-bootstrap\n",
+
+ "yum install -y java-1.8.0>> /tmp/yum-java8.log 2>&1\n",
+
+ "alternatives --set java /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java\n",
+
+ "yum -y remove java-1.7.0-openjdk>> /tmp/yum-java7.log 2>&1\n",
+
+ "##Install Artifactory\n",
+ "wget https://bintray.com/jfrog/artifactory-pro-rpms/rpm -O bintray-jfrog-artifactory-pro-rpms.repo\n",
+ "mv bintray-jfrog-artifactory-pro-rpms.repo /etc/yum.repos.d/\n",
+ "sleep 10\n",
+ "yum install -y jfrog-artifactory-pro-", { "Ref": "ArtifactoryVersion" }, ">> /tmp/yum-artifactory.log 2>&1\n",
+ "yum install -y nginx>> /tmp/yum-nginx.log 2>&1\n",
+ "curl -L -o /opt/jfrog/artifactory/tomcat/lib/mysql-connector-java-5.1.38.jar https://bintray.com/artifact/download/bintray/jcenter/mysql/mysql-connector-java/5.1.38/mysql-connector-java-5.1.38.jar\n",
+
+ "# Install the files and packages from the metadata\n",
+ "/opt/aws/bin/cfn-init -v ",
+ " --stack ", { "Ref" : "AWS::StackName" },
+ " --resource PrimaryLaunchConfig ",
+ " --region ", { "Ref" : "AWS::Region" }, "\n",
+
+ "# Signal the status from cfn-init\n",
+ "/opt/aws/bin/cfn-signal -e $? ",
+ " --stack ", { "Ref" : "AWS::StackName" },
+ " --resource PrimaryGroup ",
+ " --region ", { "Ref" : "AWS::Region" }, "\n"
+ ]]}}
+ }
+ },
+
+ "SecondaryGroup" : {
+ "Type" : "AWS::AutoScaling::AutoScalingGroup",
+ "Properties" : {
+ "AvailabilityZones" : [{ "Fn::GetAtt" : [ "PublicSubnet1", "AvailabilityZone" ] },{ "Fn::GetAtt" : [ "PublicSubnet2", "AvailabilityZone" ] }],
+ "VPCZoneIdentifier" : [{ "Ref" : "PublicSubnet1" }, { "Ref" : "PublicSubnet2" }],
+ "LaunchConfigurationName" : { "Ref" : "SecondaryLaunchConfig" },
+ "MinSize" : "0",
+ "MaxSize" : "9",
+ "DesiredCapacity" : { "Ref" : "SecondaryNodeCount" },
+ "LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancer" } ],
+ "HealthCheckGracePeriod" : "480",
+ "HealthCheckType" : "ELB"
+ },
+ "UpdatePolicy": {
+ "AutoScalingRollingUpdate": {
+ "MinInstancesInService": "1",
+ "MaxBatchSize": "1",
+ "PauseTime": "PT7M"
+ }
+ }
+ },
+
+ "SecondaryLaunchConfig": {
+ "Type" : "AWS::AutoScaling::LaunchConfiguration",
+ "Metadata" : {
+ "Comment1" : "Configure the bootstrap helpers to install the Artifactory Secondary Server",
+
+ "AWS::CloudFormation::Init" : {
+ "config" : {
+ "packages" : {
+ "yum" : {
+ "wget" : [],
+ "curl" : []
+ }
+ },
+
+ "files" : {
+
+ "/etc/nginx/nginx.conf" : {
+ "content" : { "Fn::Join" : ["", [
+ "#user nobody;\n",
+ "worker_processes 1;\n",
+ "error_log /var/log/nginx/error.log info;\n",
+ "#pid logs/nginx.pid;\n",
+ "events {\n",
+ " worker_connections 1024;\n",
+ "}\n",
+ "http {\n",
+ " include mime.types;\n",
+ " include /etc/nginx/conf.d/*.conf;\n",
+ " default_type application/octet-stream;\n",
+ " log_format main '$remote_addr - $remote_user [$time_local] \"$request\" '\n",
+ "'$status $body_bytes_sent \"$http_referer\" '\n",
+ "'\"$http_user_agent\" \"$http_x_forwarded_for\"';\n",
+ " access_log /var/log/nginx/access.log main;\n",
+ " sendfile on;\n",
+ " #tcp_nopush on;\n",
+ " #keepalive_timeout 0;\n",
+ " keepalive_timeout 65;\n",
+ "}\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/db.properties" : {
+ "content" : { "Fn::Join" : ["", [
+ "type=mysql\n",
+ "driver=com.mysql.jdbc.Driver\n",
+ "url=jdbc:mysql://", {"Fn::GetAtt" : ["MySQLDatabase", "Endpoint.Address"]},":3306/", { "Ref" : "DBName" },"?characterEncoding=UTF-8&elideSetAutoCommits=true\n",
+ "username=", {"Ref" : "DBUser"}, "\n",
+ "password=", {"Ref" : "DBPassword"}, "\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/binarystore.xml" : {
+ "content" : { "Fn::Join" : ["", [
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "crossNetworkStrategy\n",
+ "crossNetworkStrategy\n",
+ "2\n",
+ "1\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ " remote\n",
+ "\n",
+ "\n",
+ "\n",
+ " local\n",
+ "\n",
+ "\n",
+ "\n",
+ "",{ "Fn::Join": [ "", [ "s3.dualstack.", { "Ref": "AWS::Region" }, ".amazonaws.com" ] ] },"\n",
+ "", {"Ref" : "IAMAcessKey"}, "\n",
+ "", { "Fn::GetAtt": [ "IAMAcessKey", "SecretAccessKey" ] }, "\n",
+ "", { "Ref": "S3Bucket" }, "\n",
+ "\n",
+ "\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/ha-node.properties" : {
+ "content" : { "Fn::Join" : ["", [
+ "node.id=art1\n",
+ "artifactory.ha.data.dir=/var/opt/jfrog/artifactory/data\n",
+ "context.url=http://127.0.0.1:8081/artifactory\n",
+ "membership.port=10001\n",
+ "hazelcast.interface=172.25.0.3\n",
+ "primary=false\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/security/master.key" : {
+ "content" : { "Fn::Join" : ["", [
+ {"Ref" : "MasterKey"}
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/etc/pki/tls/certs/result.pem" : {
+ "content" : { "Fn::Join" : ["", [
+ {"Ref" : "Certificate"}
+ ]]},
+ "mode" : "000777",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/etc/pki/tls/private/result.key" : {
+ "content" : { "Fn::Join" : ["", [
+ {"Ref" : "CertificateKey"}
+ ]]},
+ "mode" : "000777",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/var/opt/jfrog/artifactory/etc/artifactory.cluster.license" : {
+ "content" : { "Fn::Join" : ["", [
+ "", { "Ref" : "ArtifactoryLicense1" }, "\n",
+ "\n",
+ "", { "Ref" : "ArtifactoryLicense2" }, "\n",
+ "\n",
+ "", { "Ref" : "ArtifactoryLicense3" }, "\n",
+ "\n",
+ "", { "Ref" : "ArtifactoryLicense4" }, "\n",
+ "\n",
+ "", { "Ref" : "ArtifactoryLicense5" }, "\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "artifactory",
+ "group" : "artifactory"
+ },
+
+ "/etc/nginx/conf.d/artifactory.conf" : {
+ "content" : { "Fn::Join" : ["", [
+ "ssl_certificate /etc/pki/tls/certs/cert.pem;\n",
+ "ssl_certificate_key /etc/pki/tls/private/cert.key;\n",
+ "ssl_session_cache shared:SSL:1m;\n",
+ "ssl_prefer_server_ciphers on;\n",
+ "## server configuration\n",
+ "server {\n",
+ " listen 443 ssl;\n",
+ " listen 80 ;\n",
+ " server_name ",{ "Ref" : "ArtifactoryServerName" },".",{ "Ref" : "CertificateDomain" }," ~(?.+)\\.",{ "Ref" : "CertificateDomain" },";\n",
+ " if ($http_x_forwarded_proto = '') {\n",
+ " set $http_x_forwarded_proto $scheme;\n",
+ " }\n",
+ " ## Application specific logs\n",
+ " ## access_log /var/log/nginx/artifactory-access.log timing;\n",
+ " ## error_log /var/log/nginx/artifactory-error.log;\n",
+ " rewrite ^/$ /artifactory/webapp/ redirect;\n",
+ " rewrite ^/artifactory/?(/webapp)?$ /artifactory/webapp/ redirect;\n",
+ " rewrite ^/(v1|v2)/(.*) /artifactory/api/docker/$repo/$1/$2;\n",
+ " chunked_transfer_encoding on;\n",
+ " client_max_body_size 0;\n",
+ " location /artifactory/ {\n",
+ " proxy_read_timeout 900;\n",
+ " proxy_pass_header Server;\n",
+ " proxy_cookie_path ~*^/.* /;\n",
+ " proxy_pass http://127.0.0.1:8081/artifactory/;\n",
+ " proxy_set_header X-Artifactory-Override-Base-Url $http_x_forwarded_proto://$host:$server_port/artifactory;\n",
+ " proxy_set_header X-Forwarded-Port $server_port;\n",
+ " proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;\n",
+ " proxy_set_header Host $http_host;\n",
+ " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n",
+ " }\n",
+ "}\n",
+ "\n"
+ ]]},
+ "mode" : "000755",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/etc/cfn/cfn-hup.conf" : {
+ "content" : { "Fn::Join" : ["", [
+ "[main]\n",
+ "stack=", { "Ref" : "AWS::StackId" }, "\n",
+ "region=", { "Ref" : "AWS::Region" }, "\n"
+ ]]},
+ "mode" : "000400",
+ "owner" : "root",
+ "group" : "root"
+ },
+
+ "/etc/cfn/hooks.d/cfn-auto-reloader.conf" : {
+ "content": { "Fn::Join" : ["", [
+ "[cfn-auto-reloader-hook]\n",
+ "triggers=post.update\n",
+ "path=Resources.SecondaryLaunchConfig.Metadata.AWS::CloudFormation::Init\n",
+ "action=/opt/aws/bin/cfn-init -v ",
+ " --stack ", { "Ref" : "AWS::StackName" },
+ " --resource SecondaryLaunchConfig ",
+ " --region ", { "Ref" : "AWS::Region" }, "\n",
+ "runas=root\n"
+ ]]}
+ }
+ },
+
+ "commands" : {
+ "set_artifactory_node_id" : {
+ "command" : { "Fn::Join" : ["", ["sed -i -e \"s/art1/art-$(date +%s$RANDOM)/\" /var/opt/jfrog/artifactory/etc/ha-node.properties"]]}
+ },
+ "set_artifactory_context" : {
+ "command" : { "Fn::Join" : ["", ["sed -i -e \"s/127.0.0.1/$(curl http://169.254.169.254/latest/meta-data/public-ipv4)/\" /var/opt/jfrog/artifactory/etc/ha-node.properties"]]}
+ },
+ "set_hazelcast_interface" : {
+ "command" : { "Fn::Join" : ["", ["sed -i -e \"s/172.25.0.3/$(curl http://169.254.169.254/latest/meta-data/local-ipv4)/\" /var/opt/jfrog/artifactory/etc/ha-node.properties"]]}
+ },
+ "allow_ping_anonymous" : {
+ "command" : { "Fn::Join" : ["", ["echo \"artifactory.ping.allowUnauthenticated=true\" >> /var/opt/jfrog/artifactory/etc/artifactory.system.properties"]]}
+ },
+ "set_extra_java_options" : {
+ "command" : { "Fn::Join" : ["", ["echo \"export JAVA_OPTIONS=", "\\\"", { "Ref" : "ExtraJavaOptions" }, "\\\"", "\" >> /var/opt/jfrog/artifactory/etc/default"]]}
+ },
+ "set_permissions" : {
+ "command" : { "Fn::Join" : ["", ["chown artifactory:artifactory -R /var/opt/jfrog/artifactory/* && chown artifactory:artifactory -R /var/opt/jfrog/artifactory/etc/security"]]}
+ },
+ "generate_self_signed_cert" : {
+ "command" : { "Fn::Join" : ["", ["openssl req -nodes -x509 -newkey rsa:4096 -keyout /etc/pki/tls/private/example.key -out /etc/pki/tls/certs/example.pem -days 356 -subj \"/C=US/ST=California/L=SantaClara/O=IT/CN=*.localhost\""]]}
+ },
+ "format_ssl_certificate" : {
+ "command" : { "Fn::Join" : ["", ["cat /etc/pki/tls/certs/result.pem | sed 's/CERTIFICATE----- /CERTIFICATE-----\\n/g' | sed 's/-----END/\\n-----END/' > temp.pem | mv -f temp.pem /etc/pki/tls/certs/cert.pem"]]}
+ },
+ "format_ssl_certificate_key" : {
+ "command" : { "Fn::Join" : ["", ["cat /etc/pki/tls/private/result.key | sed 's/KEY----- /KEY-----\\n/g' | sed 's/-----END/\\n-----END/' > temp.key | mv -f temp.key /etc/pki/tls/private/cert.key"]]}
+ },
+ "sleep_for_minute" : {
+ "command" : { "Fn::Join" : ["", ["sleep 120"]]}
+ }
+ },
+
+ "services" : {
+ "sysvinit" : {
+ "artifactory" : { "enabled" : "true", "ensureRunning" : "true" },
+ "nginx" : { "enabled" : "true", "ensureRunning" : "true"},
+ "cfn-hup" : { "enabled" : "true", "ensureRunning" : "true",
+ "files" : ["/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf"]}
+ }
+ }
+ }
+ }
+ },
+ "Properties": {
+ "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
+ { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
+ "InstanceType" : { "Ref" : "InstanceType" },
+ "SecurityGroups" : [ {"Ref" : "ArtifactorySecurityGroup"} ],
+ "KeyName" : { "Ref" : "KeyName" },
+ "BlockDeviceMappings" : [
+ {
+ "DeviceName" : "/dev/xvda",
+ "Ebs" : { "VolumeSize" : { "Ref" : "InstanceStorage" }, "VolumeType" : "gp2", "DeleteOnTermination" : "true"}
+ }
+ ],
+ "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
+ "#!/bin/bash -xe\n",
+ "yum update -y aws-cfn-bootstrap\n",
+
+ "yum install -y java-1.8.0>> /tmp/yum-java8.log 2>&1\n",
+
+ "alternatives --set java /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java\n",
+
+ "yum -y remove java-1.7.0-openjdk>> /tmp/yum-java7.log 2>&1\n",
+
+ "##Install Artifactory\n",
+ "wget https://bintray.com/jfrog/artifactory-pro-rpms/rpm -O bintray-jfrog-artifactory-pro-rpms.repo\n",
+ "mv bintray-jfrog-artifactory-pro-rpms.repo /etc/yum.repos.d/\n",
+ "sleep 10\n",
+ "yum install -y jfrog-artifactory-pro-", { "Ref": "ArtifactoryVersion" }, ">> /tmp/yum-artifactory.log 2>&1\n",
+ "yum install -y nginx>> /tmp/yum-nginx.log 2>&1\n",
+ "curl -L -o /opt/jfrog/artifactory/tomcat/lib/mysql-connector-java-5.1.38.jar https://bintray.com/artifact/download/bintray/jcenter/mysql/mysql-connector-java/5.1.38/mysql-connector-java-5.1.38.jar\n",
+
+ "# Install the files and packages from the metadata\n",
+ "/opt/aws/bin/cfn-init -v ",
+ " --stack ", { "Ref" : "AWS::StackName" },
+ " --resource SecondaryLaunchConfig ",
+ " --region ", { "Ref" : "AWS::Region" }, "\n",
+
+ "# Signal the status from cfn-init\n",
+ "/opt/aws/bin/cfn-signal -e $? ",
+ " --stack ", { "Ref" : "AWS::StackName" },
+ " --resource SecondaryGroup ",
+ " --region ", { "Ref" : "AWS::Region" }, "\n"
+ ]]}}
+ }
+ },
+
+
+ "ArtifactorySecurityGroup" : {
+ "Type" : "AWS::EC2::SecurityGroup",
+ "Properties" : {
+ "GroupDescription" : "Enable HTTP access via port 80 locked down to the ELB and SSH access",
+ "SecurityGroupIngress" : [
+ {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"},
+ {"IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "CidrIp" : "0.0.0.0/0"},
+ {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "SSHLocation"}},
+ {"IpProtocol" : "tcp", "FromPort" : "10001", "ToPort" : "10001", "CidrIp" : "0.0.0.0/0"},
+ {"IpProtocol" : "tcp", "FromPort" : "3306", "ToPort" : "3306", "CidrIp" : "0.0.0.0/0"},
+ {"IpProtocol" : "tcp", "FromPort" : "8081", "ToPort" : "8081", "CidrIp" : "0.0.0.0/0"}
+ ],
+ "VpcId" : { "Ref" : "VPC" }
+ }
+ },
+
+ "MyDBSubnetGroup" : {
+ "Type" : "AWS::RDS::DBSubnetGroup",
+ "Properties" : {
+ "DBSubnetGroupDescription" : "Subnets available for the RDS DB Instance",
+ "SubnetIds" : [{ "Ref" : "PrivateSubnet" },{ "Ref" : "PublicSubnet1" }, { "Ref" : "PublicSubnet2" }]
+ }
+ },
+
+ "MySQLDatabase": {
+ "Type": "AWS::RDS::DBInstance",
+ "Properties": {
+ "Engine" : "MySQL",
+ "EngineVersion" : "5.5",
+ "DBName" : { "Ref": "DBName" },
+ "MultiAZ" : { "Ref": "MultiAZDatabase" },
+ "MasterUsername": { "Ref": "DBUser" },
+ "MasterUserPassword": { "Ref" : "DBPassword" },
+ "DBInstanceClass": { "Ref" : "DBInstanceClass" },
+ "AllocatedStorage": { "Ref" : "DBAllocatedStorage" },
+ "DBSubnetGroupName" : { "Ref" : "MyDBSubnetGroup" },
+ "VPCSecurityGroups": [ { "Ref" : "ArtifactorySecurityGroup" } ]
+ }
+ }
+ },
+
+ "Outputs" : {
+ "URL" : {
+ "Description" : "URL of the Artifactory",
+ "Value" : { "Fn::Join" : [ "", [ "http://", { "Fn::GetAtt" : [ "ElasticLoadBalancer", "DNSName" ]}]]}
+ }
+ }
+}
\ No newline at end of file
diff --git a/CloudFormation/images/10.png b/CloudFormation/images/10.png
new file mode 100644
index 0000000..4291a97
Binary files /dev/null and b/CloudFormation/images/10.png differ
diff --git a/CloudFormation/images/11.png b/CloudFormation/images/11.png
new file mode 100644
index 0000000..7884700
Binary files /dev/null and b/CloudFormation/images/11.png differ
diff --git a/CloudFormation/images/12.png b/CloudFormation/images/12.png
new file mode 100644
index 0000000..8440a73
Binary files /dev/null and b/CloudFormation/images/12.png differ
diff --git a/CloudFormation/images/13.png b/CloudFormation/images/13.png
new file mode 100644
index 0000000..b72f43b
Binary files /dev/null and b/CloudFormation/images/13.png differ
diff --git a/CloudFormation/images/14.png b/CloudFormation/images/14.png
new file mode 100644
index 0000000..cd45337
Binary files /dev/null and b/CloudFormation/images/14.png differ
diff --git a/CloudFormation/images/15.png b/CloudFormation/images/15.png
new file mode 100644
index 0000000..097d632
Binary files /dev/null and b/CloudFormation/images/15.png differ
diff --git a/CloudFormation/images/2.png b/CloudFormation/images/2.png
new file mode 100644
index 0000000..2dee95c
Binary files /dev/null and b/CloudFormation/images/2.png differ
diff --git a/CloudFormation/images/3.png b/CloudFormation/images/3.png
new file mode 100644
index 0000000..e9ee659
Binary files /dev/null and b/CloudFormation/images/3.png differ
diff --git a/CloudFormation/images/4.png b/CloudFormation/images/4.png
new file mode 100644
index 0000000..2463feb
Binary files /dev/null and b/CloudFormation/images/4.png differ
diff --git a/CloudFormation/images/5.png b/CloudFormation/images/5.png
new file mode 100644
index 0000000..8007b3a
Binary files /dev/null and b/CloudFormation/images/5.png differ
diff --git a/CloudFormation/images/6.png b/CloudFormation/images/6.png
new file mode 100644
index 0000000..23d1030
Binary files /dev/null and b/CloudFormation/images/6.png differ
diff --git a/CloudFormation/images/7.png b/CloudFormation/images/7.png
new file mode 100644
index 0000000..d723eac
Binary files /dev/null and b/CloudFormation/images/7.png differ
diff --git a/CloudFormation/images/8.png b/CloudFormation/images/8.png
new file mode 100644
index 0000000..07eda99
Binary files /dev/null and b/CloudFormation/images/8.png differ
diff --git a/CloudFormation/images/9.png b/CloudFormation/images/9.png
new file mode 100644
index 0000000..0fd1fb1
Binary files /dev/null and b/CloudFormation/images/9.png differ
diff --git a/README.md b/README.md
index 4122d4d..cd0c83d 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,6 @@
-# JFrog-Cloud-Installers
\ No newline at end of file
+# JFrog-Cloud-Installers
+
+Template to deploy/manage JFrog Artifactory enterprise cluster on various cloud providers.
+
+[Terraform](Terraform/README.md)
+[CloudFormation](CloudFormation/README.md)
\ No newline at end of file
diff --git a/Terraform/README.md b/Terraform/README.md
new file mode 100644
index 0000000..22b6947
--- /dev/null
+++ b/Terraform/README.md
@@ -0,0 +1,84 @@
+# Terraform Template For Artifactory Enterprise
+
+### Prerequisites:
+* AWS account
+* Basic knowledge to AWS
+* Pre created Keys
+* Basic knowledge of Artifactory
+
+### Steps to Deploy Artifactory Enterprise using Terraform template
+
+1. Set your AWS account credentials.
+ Easy way to do it is by setting environment variables.
+ ```
+ export AWS_ACCESS_KEY_ID="your_access_key"
+ export AWS_SECRET_ACCESS_KEY="your_secret_key"
+ export AWS_DEFAULT_REGION="aws_region"
+ ```
+ To learn more about Terraform aws provider follow there documentation.
+ https://www.terraform.io/docs/providers/aws/index.html
+
+2. Make Changes in `variables.tf` file to change default values to desired once. Also pass Artifactory Enterprise licenses as string in Variables `artifactory_license_1-5`."
+ e.g Change disk space to 500Gb:
+ ```
+ variable "volume_size" {
+ description = "Disk size for each EC2 instances"
+ default = 500
+ }
+ ```
+
+3. Run command `terraform init -var 'key_name=myAwsKey'`
+ This is install required plugin for AWS provider.
+
+4. Run command `terraform plan -var 'key_name=myAwsKey'`.
+
+5. Run command `terraform apply -var 'key_name=myAwsKey'` to deploy Artifactory Enterprise cluster on AWS.
+
+ It will take approximately 15 min to bring up cluster.
+
+ You will get ELB Url to access Artifactory.By default This template will start only 1 node in Artifactory cluster.
+ ```
+ Outputs:
+
+ address = artifactory-elb-265664219.us-west-2.elb.amazonaws.com
+ ```
+
+6. Access Artifactory UI using ELB Url provided in outputs.
+
+7. Scale your cluster using following command:
+
+ `terraform apply -var 'key_name=myAwsKey' -var 'secondary_node_count=2'`
+
+ In this example we are scaling artifactory cluster to 2 nodes.
+
+ Note: You can only scale nodes to number of artifactory licenses you have available for cluster.
+
+8. SSH into Artifactory primary instance and write [inactiveServerCleaner](inactiveServerCleaner.groovy) plugin in '/var/opt/jfrog/artifactory/etc/plugins' directory.
+
+9. Command to destroy cluster:
+ `terraform destroy -var 'key_name=myAwsKey'`
+
+### Note:
+1. This template only supports Artifactory version 5.8.x and above.
+2. Turn off daily backups. Read Documentation provided [here](https://www.jfrog.com/confluence/display/RTF/Managing+Backups)
+3. Use SSL Certificate with valid wild card to you artifactory as docker registry with subdomain method.
+
+### Steps to setup Artifactory as secure docker registry
+considering you have SSL certificate for `*.jfrog.team`
+1. Pass your SSL Certificate in variable `ssl_certificate` as string
+2. Pass your SSL Certificate Key in variable `ssl_certificate_key` as string
+3. Set `certificate_domain` as `jfrog.team`
+4. Set `artifactory_server_name` as `artifactory` if you want to access artifactory with `https://artifactory.jfrog.team`
+5. Create Rout53 with entry `artifactory.jfrog.team` pointing to ELB value provided as output in CloudFormation Stack.
+6. Create Rout53 with entry `*.jfrog.team` pointing to ELB value provided as output in CloudFormation Stack.
+7. If you have virtual docker registry with name `docker-virtual` in artifactory. You can access it via `docker-virtual.jfrog.team`
+ e.g ```docker pull docker-virtual.jfrog.team/nginx```
+
+
+### Steps to upgrade Artifactory Version
+1. Change value of `artifactory_version` from old version to new Artifactory version you want to deploy.
+ for e.g. 5.8.1 to 5.8.2
+ Run command `terraform apply -var 'key_name=myAwsKey' -var 'secondary_node_count=2' -ver 'artifactory_version=5.8.2'`.
+
+2. You will see instances will get upgraded one by one. Depending on your cluster size it will take 20-30 minutes to update stack.
+
\ No newline at end of file
diff --git a/Terraform/inactiveServerCleaner.groovy b/Terraform/inactiveServerCleaner.groovy
new file mode 100644
index 0000000..6f85566
--- /dev/null
+++ b/Terraform/inactiveServerCleaner.groovy
@@ -0,0 +1,37 @@
+import org.artifactory.state.ArtifactoryServerState
+import org.artifactory.storage.db.servers.service.ArtifactoryServersCommonService
+import org.artifactory.common.ConstantValues
+import org.slf4j.Logger
+import java.util.concurrent.TimeUnit
+
+jobs {
+ clean(cron: "* 0/1 * * * ?") {
+ def artifactoryServersCommonService = ctx.beanForType(ArtifactoryServersCommonService)
+ def artifactoryInactiveServerCleaner = new ArtifactoryInactiveServersCleaner(artifactoryServersCommonService, log)
+ artifactoryInactiveServerCleaner.cleanInactiveArtifactoryServers()
+ }
+}
+
+public class ArtifactoryInactiveServersCleaner {
+
+ private ArtifactoryServersCommonService artifactoryServersCommonService
+ private Logger log
+
+ ArtifactoryInactiveServersCleaner(ArtifactoryServersCommonService artifactoryServersCommonService, Logger log) {
+ this.artifactoryServersCommonService = artifactoryServersCommonService
+ this.log = log
+ }
+
+ def cleanInactiveArtifactoryServers() {
+ List allMembers = artifactoryServersCommonService.getAllArtifactoryServers()
+ for (member in allMembers) {
+ def heartbeat = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - member.getLastHeartbeat())
+ def noheartbeat = heartbeat > ConstantValues.haHeartbeatStaleIntervalSecs.getInt()
+ if (member.getServerState() == ArtifactoryServerState.UNAVAILABLE || noheartbeat) {
+ log.info "Running inactive artifactory servers cleaning task, found ${member.serverId} inactive servers to " +
+ "remove"
+ artifactoryServersCommonService.removeServer(member.serverId)
+ }
+ }
+ }
+}
diff --git a/Terraform/main.tf b/Terraform/main.tf
new file mode 100644
index 0000000..4bf0eb4
--- /dev/null
+++ b/Terraform/main.tf
@@ -0,0 +1,447 @@
+# Specify the provider and access details
+provider "aws" {
+ region = "${var.aws_region}"
+}
+
+# Create a VPC to launch our instances into
+resource "aws_vpc" "default" {
+ cidr_block = "10.0.0.0/16"
+}
+
+# Create an internet gateway to give our subnet access to the outside world
+resource "aws_internet_gateway" "default" {
+ vpc_id = "${aws_vpc.default.id}"
+}
+
+# Grant the VPC internet access on its main route table
+resource "aws_route" "internet_access" {
+ route_table_id = "${aws_vpc.default.main_route_table_id}"
+ destination_cidr_block = "0.0.0.0/0"
+ gateway_id = "${aws_internet_gateway.default.id}"
+}
+
+# Declare the data source
+data "aws_availability_zones" "available" {}
+
+# Create a subnet to launch our instances into
+resource "aws_subnet" "default" {
+ vpc_id = "${aws_vpc.default.id}"
+ cidr_block = "10.0.1.0/24"
+ map_public_ip_on_launch = true
+}
+
+# Create a subnet to launch our instances into
+resource "aws_subnet" "default_2" {
+ vpc_id = "${aws_vpc.default.id}"
+ cidr_block = "10.0.2.0/24"
+ map_public_ip_on_launch = true
+ availability_zone = "${data.aws_availability_zones.available.names[0]}"
+}
+
+resource "aws_subnet" "default_3" {
+ vpc_id = "${aws_vpc.default.id}"
+ cidr_block = "10.0.3.0/24"
+ map_public_ip_on_launch = true
+ availability_zone = "${data.aws_availability_zones.available.names[1]}"
+}
+
+# A security group for the ELB so it is accessible via the web
+resource "aws_security_group" "elb" {
+ name = "artifactory_elb"
+ description = "Used in the terraform"
+ vpc_id = "${aws_vpc.default.id}"
+
+ # HTTP access from anywhere
+ ingress {
+ from_port = 80
+ to_port = 80
+ protocol = "tcp"
+ cidr_blocks = ["0.0.0.0/0"]
+ }
+ # HTTPS access from anywhere
+ ingress {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ cidr_blocks = ["0.0.0.0/0"]
+ }
+
+ # outbound internet access
+ egress {
+ from_port = 0
+ to_port = 0
+ protocol = "-1"
+ cidr_blocks = ["0.0.0.0/0"]
+ }
+}
+
+
+#IAM user for S3
+resource "aws_iam_user" "s3" {
+ name = "s3-access"
+}
+
+#IAM access key for S3
+resource "aws_iam_access_key" "s3" {
+ user = "${aws_iam_user.s3.name}"
+}
+
+# S3 bucket
+resource "aws_s3_bucket" "b" {
+ bucket = "${var.bucket_name}"
+ acl = "private"
+}
+
+#IAM Policy
+resource "aws_iam_user_policy" "lb_ro" {
+ user = "${aws_iam_user.s3.name}"
+
+ policy = <> /tmp/yum-java8.log
+alternatives --set java /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java
+yum -y remove java-1.7.0-openjdk>> /tmp/yum-java7.log 2>&1
+
+##Install Artifactory
+wget https://bintray.com/jfrog/artifactory-pro-rpms/rpm -O bintray-jfrog-artifactory-pro-rpms.repo
+mv bintray-jfrog-artifactory-pro-rpms.repo /etc/yum.repos.d/
+sleep 10
+yum install -y jfrog-artifactory-pro-${artifactory_version}>> /tmp/yum-artifactory.log 2>&1
+yum install -y nginx>> /tmp/yum-nginx.log 2>&1
+curl -L -o /opt/jfrog/artifactory/tomcat/lib/mysql-connector-java-5.1.38.jar https://bintray.com/artifact/download/bintray/jcenter/mysql/mysql-connector-java/5.1.38/mysql-connector-java-5.1.38.jar
+openssl req -nodes -x509 -newkey rsa:4096 -keyout /etc/pki/tls/private/example.key -out /etc/pki/tls/certs/example.pem -days 356 -subj "/C=US/ST=California/L=SantaClara/O=IT/CN=*.localhost"
+
+cat </var/opt/jfrog/artifactory/etc/binarystore.xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ crossNetworkStrategy
+ crossNetworkStrategy
+ 2
+
+
+
+
+ remote
+
+
+
+ local
+
+
+ s3.dualstack.${s3_bucket_region}.amazonaws.com
+ ${s3_access_key}
+ ${s3_secret_key}
+ ${s3_bucket_name}
+
+
+EOF
+
+cat </var/opt/jfrog/artifactory/etc/db.properties
+ type=mysql
+ driver=com.mysql.jdbc.Driver
+ url=jdbc:mysql://${db_url}/${db_name}??characterEncoding=UTF-8&elideSetAutoCommits=true
+ username=${db_user}
+ password=${db_password}
+EOF
+
+mkdir -p /var/opt/jfrog/artifactory/etc/security
+
+cat </var/opt/jfrog/artifactory/etc/security/master.key
+${master_key}
+EOF
+
+cat </var/opt/jfrog/artifactory/etc/artifactory.cluster.license
+${artifactory_license_1}
+
+${artifactory_license_2}
+
+${artifactory_license_3}
+
+${artifactory_license_4}
+
+${artifactory_license_5}
+EOF
+
+cat </var/opt/jfrog/artifactory/etc/ha-node.properties
+ node.id=art1
+ artifactory.ha.data.dir=/var/opt/jfrog/artifactory/data
+ context.url=http://127.0.0.1:8081/artifactory
+ membership.port=10001
+ hazelcast.interface=172.25.0.3
+ primary=true
+EOF
+
+cat </etc/pki/tls/certs/result.pem
+${ssl_certificate}
+EOF
+
+cat </etc/pki/tls/private/result.key
+${ssl_certificate_key}
+EOF
+
+cat </etc/nginx/nginx.conf
+ #user nobody;
+ worker_processes 1;
+ error_log /var/log/nginx/error.log info;
+ #pid logs/nginx.pid;
+ events {
+ worker_connections 1024;
+ }
+
+ http {
+ include mime.types;
+ include /etc/nginx/conf.d/*.conf;
+ default_type application/octet-stream;
+ log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for"';
+ access_log /var/log/nginx/access.log main;
+ sendfile on;
+ #tcp_nopush on;
+ #keepalive_timeout 0;
+ keepalive_timeout 65;
+ }
+EOF
+
+cat </etc/nginx/conf.d/artifactory.conf
+ssl_certificate /etc/pki/tls/certs/cert.pem;
+ssl_certificate_key /etc/pki/tls/private/cert.key;
+ssl_session_cache shared:SSL:1m;
+ssl_prefer_server_ciphers on;
+## server configuration
+server {
+ listen 443 ssl;
+ listen 80 ;
+ server_name ~(?.+)\\.${certificate_domain} ${artifactory_server_name}.${certificate_domain};
+ if (\$http_x_forwarded_proto = '') {
+ set \$http_x_forwarded_proto \$scheme;
+ }
+ ## Application specific logs
+ ## access_log /var/log/nginx/artifactory-access.log timing;
+ ## error_log /var/log/nginx/artifactory-error.log;
+ rewrite ^/$ /artifactory/webapp/ redirect;
+ rewrite ^/artifactory/?(/webapp)?$ /artifactory/webapp/ redirect;
+ rewrite ^/(v1|v2)/(.*) /artifactory/api/docker/\$repo/\$1/\$2;
+ chunked_transfer_encoding on;
+ client_max_body_size 0;
+ location /artifactory/ {
+ proxy_read_timeout 900;
+ proxy_pass_header Server;
+ proxy_cookie_path ~*^/.* /;
+ proxy_pass http://127.0.0.1:8081/artifactory/;
+ proxy_set_header X-Artifactory-Override-Base-Url \$http_x_forwarded_proto://\$host:\$server_port/artifactory;
+ proxy_set_header X-Forwarded-Port \$server_port;
+ proxy_set_header X-Forwarded-Proto \$http_x_forwarded_proto;
+ proxy_set_header Host \$http_host;
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+ }
+}
+EOF
+
+cat /etc/pki/tls/certs/result.pem | sed 's/CERTIFICATE----- /CERTIFICATE-----\n/g' | sed 's/-----END/\n-----END/' > temp.pem
+mv -f temp.pem /etc/pki/tls/certs/cert.pem
+cat /etc/pki/tls/private/result.key | sed 's/KEY----- /KEY-----\n/g' | sed 's/-----END/\n-----END/' > temp.key
+mv -f temp.key /etc/pki/tls/private/cert.key
+echo "artifactory.ping.allowUnauthenticated=true" >> /var/opt/jfrog/artifactory/etc/artifactory.system.properties
+echo "export JAVA_OPTIONS=\"${EXTRA_JAVA_OPTS}\"" >> /var/opt/jfrog/artifactory/etc/default
+sed -i -e "s/art1/art-$(date +%s$RANDOM)/" /var/opt/jfrog/artifactory/etc/ha-node.properties
+sed -i -e "s/127.0.0.1/$(curl http://169.254.169.254/latest/meta-data/public-ipv4)/" /var/opt/jfrog/artifactory/etc/ha-node.properties
+sed -i -e "s/172.25.0.3/$(curl http://169.254.169.254/latest/meta-data/local-ipv4)/" /var/opt/jfrog/artifactory/etc/ha-node.properties
+chown artifactory:artifactory -R /var/opt/jfrog/artifactory/etc/* && chown artifactory:artifactory -R /var/opt/jfrog/artifactory/* && chown artifactory:artifactory -R /var/opt/jfrog/artifactory/etc/security
+service artifactory start
+service nginx start
\ No newline at end of file
diff --git a/Terraform/userdata_secondary.sh b/Terraform/userdata_secondary.sh
new file mode 100644
index 0000000..9b55efd
--- /dev/null
+++ b/Terraform/userdata_secondary.sh
@@ -0,0 +1,172 @@
+#!/bin/bash
+
+yum update -y
+yum install -y java-1.8.0>> /tmp/yum-java8.log
+alternatives --set java /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java
+yum -y remove java-1.7.0-openjdk>> /tmp/yum-java7.log 2>&1
+
+##Install Artifactory
+wget https://bintray.com/jfrog/artifactory-pro-rpms/rpm -O bintray-jfrog-artifactory-pro-rpms.repo
+mv bintray-jfrog-artifactory-pro-rpms.repo /etc/yum.repos.d/
+sleep 10
+yum install -y jfrog-artifactory-pro-${artifactory_version}>> /tmp/yum-artifactory.log 2>&1
+yum install -y nginx>> /tmp/yum-nginx.log 2>&1
+curl -L -o /opt/jfrog/artifactory/tomcat/lib/mysql-connector-java-5.1.38.jar https://bintray.com/artifact/download/bintray/jcenter/mysql/mysql-connector-java/5.1.38/mysql-connector-java-5.1.38.jar
+openssl req -nodes -x509 -newkey rsa:4096 -keyout /etc/pki/tls/private/example.key -out /etc/pki/tls/certs/example.pem -days 356 -subj "/C=US/ST=California/L=SantaClara/O=IT/CN=*.localhost"
+
+
+cat </var/opt/jfrog/artifactory/etc/binarystore.xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ crossNetworkStrategy
+ crossNetworkStrategy
+ 2
+
+
+
+
+ remote
+
+
+
+ local
+
+
+ s3.dualstack.${s3_bucket_region}.amazonaws.com
+ ${s3_access_key}
+ ${s3_secret_key}
+ ${s3_bucket_name}
+
+
+EOF
+
+cat </var/opt/jfrog/artifactory/etc/db.properties
+ type=mysql
+ driver=com.mysql.jdbc.Driver
+ url=jdbc:mysql://${db_url}/${db_name}??characterEncoding=UTF-8&elideSetAutoCommits=true
+ username=${db_user}
+ password=${db_password}
+EOF
+
+mkdir -p /var/opt/jfrog/artifactory/etc/security
+
+cat </var/opt/jfrog/artifactory/etc/security/master.key
+${master_key}
+EOF
+
+cat </var/opt/jfrog/artifactory/etc/artifactory.cluster.license
+${artifactory_license_1}
+
+${artifactory_license_2}
+
+${artifactory_license_3}
+
+${artifactory_license_4}
+
+${artifactory_license_5}
+EOF
+
+cat </var/opt/jfrog/artifactory/etc/ha-node.properties
+ node.id=art1
+ artifactory.ha.data.dir=/var/opt/jfrog/artifactory/data
+ context.url=http://127.0.0.1:8081/artifactory
+ membership.port=10001
+ hazelcast.interface=172.25.0.3
+ primary=false
+EOF
+
+cat </etc/pki/tls/certs/result.pem
+${ssl_certificate}
+EOF
+
+cat </etc/pki/tls/private/result.key
+${ssl_certificate_key}
+EOF
+
+cat </etc/nginx/nginx.conf
+ #user nobody;
+ worker_processes 1;
+ error_log /var/log/nginx/error.log info;
+ #pid logs/nginx.pid;
+ events {
+ worker_connections 1024;
+ }
+
+ http {
+ include mime.types;
+ include /etc/nginx/conf.d/*.conf;
+ default_type application/octet-stream;
+ log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for"';
+ access_log /var/log/nginx/access.log main;
+ sendfile on;
+ #tcp_nopush on;
+ #keepalive_timeout 0;
+ keepalive_timeout 65;
+ }
+EOF
+
+cat </etc/nginx/conf.d/artifactory.conf
+ssl_certificate /etc/pki/tls/certs/cert.pem;
+ssl_certificate_key /etc/pki/tls/private/cert.key;
+ssl_session_cache shared:SSL:1m;
+ssl_prefer_server_ciphers on;
+## server configuration
+server {
+ listen 443 ssl;
+ listen 80 ;
+ server_name ~(?.+)\\.${certificate_domain} ${artifactory_server_name}.${certificate_domain};
+ if (\$http_x_forwarded_proto = '') {
+ set \$http_x_forwarded_proto \$scheme;
+ }
+ ## Application specific logs
+ ## access_log /var/log/nginx/artifactory-access.log timing;
+ ## error_log /var/log/nginx/artifactory-error.log;
+ rewrite ^/$ /artifactory/webapp/ redirect;
+ rewrite ^/artifactory/?(/webapp)?$ /artifactory/webapp/ redirect;
+ rewrite ^/(v1|v2)/(.*) /artifactory/api/docker/\$repo/\$1/\$2;
+ chunked_transfer_encoding on;
+ client_max_body_size 0;
+ location /artifactory/ {
+ proxy_read_timeout 900;
+ proxy_pass_header Server;
+ proxy_cookie_path ~*^/.* /;
+ proxy_pass http://127.0.0.1:8081/artifactory/;
+ proxy_set_header X-Artifactory-Override-Base-Url \$http_x_forwarded_proto://\$host:\$server_port/artifactory;
+ proxy_set_header X-Forwarded-Port \$server_port;
+ proxy_set_header X-Forwarded-Proto \$http_x_forwarded_proto;
+ proxy_set_header Host \$http_host;
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+ }
+}
+EOF
+
+cat /etc/pki/tls/certs/result.pem | sed 's/CERTIFICATE----- /CERTIFICATE-----\n/g' | sed 's/-----END/\n-----END/' > temp.pem
+mv -f temp.pem /etc/pki/tls/certs/cert.pem
+cat /etc/pki/tls/private/result.key | sed 's/KEY----- /KEY-----\n/g' | sed 's/-----END/\n-----END/' > temp.key
+mv -f temp.key /etc/pki/tls/private/cert.key
+echo "artifactory.ping.allowUnauthenticated=true" >> /var/opt/jfrog/artifactory/etc/artifactory.system.properties
+echo "export JAVA_OPTIONS=\"${EXTRA_JAVA_OPTS}\"" >> /var/opt/jfrog/artifactory/etc/default
+sed -i -e "s/art1/art-$(date +%s$RANDOM)/" /var/opt/jfrog/artifactory/etc/ha-node.properties
+sed -i -e "s/127.0.0.1/$(curl http://169.254.169.254/latest/meta-data/public-ipv4)/" /var/opt/jfrog/artifactory/etc/ha-node.properties
+sed -i -e "s/172.25.0.3/$(curl http://169.254.169.254/latest/meta-data/local-ipv4)/" /var/opt/jfrog/artifactory/etc/ha-node.properties
+chown artifactory:artifactory -R /var/opt/jfrog/artifactory/etc/* && chown artifactory:artifactory -R /var/opt/jfrog/artifactory/* && chown artifactory:artifactory -R /var/opt/jfrog/artifactory/etc/security
+
+## Sleep 2 minute to avoid race condition
+sleep 120
+service artifactory start
+service nginx start
\ No newline at end of file
diff --git a/Terraform/variables.tf b/Terraform/variables.tf
new file mode 100644
index 0000000..852705f
--- /dev/null
+++ b/Terraform/variables.tf
@@ -0,0 +1,133 @@
+variable "aws_region" {
+ description = "AWS region to launch servers."
+ default = "us-west-1"
+}
+
+variable "key_name" {
+ description = "Desired name of AWS key pair"
+}
+
+variable "artifactory_version" {
+ description = "Artifactory version to deploy"
+ default = "5.8.1"
+}
+
+variable "artifactory_license_1" {
+ description = "Artifactory Enterprise License"
+}
+
+variable "artifactory_license_2" {
+ description = "Artifactory Enterprise License"
+}
+
+variable "artifactory_license_3" {
+ description = "Artifactory Enterprise License"
+ default = ""
+}
+
+variable "artifactory_license_4" {
+ description = "Artifactory Enterprise License"
+ default = ""
+}
+
+variable "artifactory_license_5" {
+ description = "Artifactory Enterprise License"
+ default = ""
+}
+
+variable "volume_size" {
+ description = "Disk size for each EC2 instances"
+ default = 250
+}
+
+variable "artifactory_instance_type" {
+ default = "m4.xlarge"
+ description = "Artifactory EC2 instance type"
+}
+
+variable "extra_java_options" {
+ default = "-server -Xms2g -Xmx14g -Xss256k -XX:+UseG1GC -XX:OnOutOfMemoryError=\\\\\\\"kill -9 %p\\\\\\\""
+ description = "Setting Java Memory Parameters for Artifactory"
+}
+
+variable "bucket_name" {
+ description = "AWS S3 Buket name"
+ default = "artifactory-enterprise-bucket"
+}
+
+variable "db_name" {
+ description = "MySQL database name"
+ default = "artdb"
+}
+
+variable "db_user" {
+ description = "Database user name"
+ default = "artifactory"
+}
+
+variable "db_instance_class" {
+ description = "The database instance type"
+ default = "db.t2.small"
+}
+
+variable "db_password" {
+ description = "Database password"
+ default = "password"
+}
+
+variable "db_allocated_storage" {
+ description = "The size of the database (Gb)"
+ default = "5"
+}
+
+variable "master_key" {
+ description = "Master key for Artifactory cluster. Generate master.key using command '$openssl rand -hex 16'"
+ default = "35767fa0164bac66b6cccb8880babefb"
+}
+
+variable "secondary_node_count" {
+ description = "Desired number of Artifactory secondary nodes"
+ default = 0
+}
+
+variable "ssl_certificate" {
+ description = "To use Artifactory as docker registry you need to provide wild card valid Certificate. Provide your SSL Certificate."
+ default = "-----BEGIN CERTIFICATE----- MIIFhzCCA2+gAwIBAgIJALC4r5BQWZE4MA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRMwEQYDVQQHDApTYW50YUNsYXJh MQswCQYDVQQKDAJJVDEUMBIGA1UEAwwLKi5sb2NhbGhvc3QwHhcNMTgwMTE3MTk0 NjI4WhcNMTkwMTA4MTk0NjI4WjBaMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2Fs aWZvcm5pYTETMBEGA1UEBwwKU2FudGFDbGFyYTELMAkGA1UECgwCSVQxFDASBgNV BAMMCyoubG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA 7KfOWDQlov8cMa8r/lcJqiWZaH9myQC74Vbe0HXsntQbcvljkjG2P7ebm5dd9Bzc sauNOJpbKf5AhFK1iwJUAkciGc1LR4k8wfWmQM3NPS8hrqrtH20zqNpdFRpNYjja JofwccPNm030GhhZkZ95TpruvmswMDwspl3jfqdcc/eiQsHcKyGnV2a+UAeoqe7J mHhmhRy1MLqAjF5U1GrUYUONA+22iRDJb4c9B91QoWvsnXpdA9NKV/mmA3/rIdx6 Ld2IPRdrIw2K5sAnXsh3bx2oCSvSfussf0x+4XDrnsaHVfjwvfNL8ECOuac2Oi/E WOp9528gOohpFAuwEt63Vl5p8/CC9m0HJDTZBKm2l5eD1kdPIj4PvP9Sn9CxGXKQ E1bxWoFxGX8EyRW0b0NK31N7b8JPZ1SoFNiB5amOMNLvR26a7cQrKumTuJeYK9Ja JaxhMXM7R0DA0Ev8ZG2xmyCygox+1KPSmJOIEpT70BFbj3rKLNqP22ET+zvPuh+2 DdgyrpHFeYkGWjMbWPjK7wJsD2zM8ccoJQfepPz8I4rT0JfrKAQgCGuGOggneaNJ KTVGNOFbj5AXdZ/Q+GvNommyRdq4J7EnqY6L+P25fo5qZ6UZ/iS0tPcvxgn0Fdhs pUPbQyQIDZyxZd3Q1lUIE38ol8P66mS2zbzf8EeOCoUCAwEAAaNQME4wHQYDVR0O BBYEFETAQM/5P7XJ8kevHFj6BPndQOFaMB8GA1UdIwQYMBaAFETAQM/5P7XJ8kev HFj6BPndQOFaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAJ1TepKv LWYhFmVQcgZwZf/qt1a1cohzJSm6da9RCnnAWC7WC/U117bgSomtrH1v0OysHFhB zBBUeBqI7+OmzAX8dhj+roKkcnFUM/IwlK1eueIIA//CWvEf/o0XExilVS2yCc9d PTpOQBXwk9QinxK36kHdBiGxa7dW0JPnOEEmuMgGORKeLy4J6Ik8iSeFY1SZVcOI +6WWvoKciPlmIeccC+6YVmkeBwhP2o5r5w/UAaO2hSnGvmm4UIj/VJv4VQu7xTUp cIfFz5NtIr80DbqcyPiEMS2ETJ4L/kO4MS5FfeEXyQuXCzmiIDVY6tE3C7+kZmK4 JzPLuWm9ndQoyQySOGfQqvlUR1+YxUdvmu3LrOS5dOA354Q36wHa4wEGUoHU/7GV fYQmmmDSDaNSpXW5PFey6scFyDBS/yYJ0H9EjYb/11HeWYj8Yv5xTWj8nhzJONC8 D6Y5ydlU4PifM2pOf88pTYpmogNwLJWXbql5I9cvMa8APo4yLVqcISU5ynsvFke+ Non+T0mHpJai/hrA9NK+s6EGC1dAX58jy61h6FhOPI1d4s/mov/KMa2t3SfZp5SF 81aR6dHvO56teiK5M1xMkrqG75zh3TMFJJLRFe9XxeB4JeN76URB3mgADOUqkBxd ibSgVqfKwOw4IujEcqMUc5mqSnbLY1Dv+oby -----END CERTIFICATE-----"
+}
+
+variable "ssl_certificate_key" {
+ description = "Provide your SSL Certificate key"
+ default = "-----BEGIN PRIVATE KEY----- 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 S+j1+iUKGGhwVmhqh75q5do3+VF3XlAh -----END PRIVATE KEY-----"
+}
+
+variable "certificate_domain" {
+ description = "Provide your Certificate Domain Name. For e.g jfrog.team for certificate with *.jfrog.team"
+ default = "artifactory"
+}
+
+variable "artifactory_server_name" {
+ description = "Provide artifactory server name to be used in Nginx. e.g artifactory for artifactory.jfrog.team"
+ default = "artifactory"
+}
+
+variable "aws_amis" {
+ type = "map"
+ default = {
+ us-east-1 = "ami-6869aa05"
+ us-west-2 = "ami-7172b611"
+ us-west-1 = "ami-31490d51"
+ us-west-2 = "ami-7172b611"
+ eu-west-1 = "ami-f9dd458a"
+ eu-west-2 = "ami-886369ec"
+ eu-central-1 = "ami-ea26ce85"
+ ap-northeast-1 = "ami-374db956"
+ ap-northeast-2 = "ami-2b408b45"
+ ap-southeast-1 = "ami-a59b49c6"
+ ap-southeast-2 = "ami-dc361ebf"
+ ap-south-1 = "ami-ffbdd790"
+ us-east-2 = "ami-f6035893"
+ ca-central-1 ="ami-730ebd17"
+ sa-east-1 = "ami-6dd04501"
+ cn-north-1 = "ami-8e6aa0e3"
+ }
+}
\ No newline at end of file