Confluence.yaml
---

Confluence Application Stack CloudFormation Deployment

This CloudFormation template will deploy an application node for Confluence

AWSTemplateFormatVersion: '2010-09-09' Description: Confluence Application Stack Metadata: Description: Provides a Confluence Application complete with EC2, ALB, and RDS AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Infrastructure Options Parameters: - VPC - InstanceSubnet - Label: default: EC2 Instance Configuration Parameters: - InstanceType - KeyName Parameters: InstanceType: Type: String Description: The Instance type to use Default: t2.large PublicOrPrivate: Type: String Description: Public or Private instance Default: Private AllowedValues: - Private - Public ServiceURL: Type: String Description: Public service URL (I.E confluence.arizona.edu) Default: 'confluence.arizona.edu' VPC: Type: 'AWS::EC2::VPC::Id' Description: The VPC to support ASG instance capacity and ALB KeyName: Type: 'AWS::EC2::KeyPair::KeyName' Description: The SSH Keypair for the Confluence Instances InstanceSubnet: Type: 'AWS::EC2::Subnet::Id' Description: The private subnet for the application LBSubnetA: Type: 'AWS::EC2::Subnet::Id' Description: subnet A for load balancer LBSubnetB: Type: 'AWS::EC2::Subnet::Id' Description: subnet B for load balancer SSLCertificatARN: Type: String Description: Full ARN of the SSL Certificate to use on the load balancer Default: "arn:aws:acm:us-west-2:722748364533:certificate/0e663657-5dc9-4b90-b1a7-cc931bd0e765" InstallerFile: Type: String Description: Filename of confluence archive to install. Default: UA_confluence-6.14.3.tar.gz ConfluenceFoundationStack: Type: String Description: Name of the confluence foundation stack. Default: ConfluenceFoundation ConfluenceRDSStack: Type: String Description: Name of the confluence RDS stack. Default: ConfluenceRDS2 ConfluenceEnvironment: Type: String Description: prd, tst, or dev environments. Default: dev HostedZoneName: Type: String Description: route53 hosted zone name Default: uits-nonprod-aws.arizona.edu AmazonLinuxAmi: Type : AWS::SSM::Parameter::Value<String> Default: /aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2 Description: Amazon Linux Latest AMI ID AllowedValues: - /aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2

Tags

The following tags are applied to all resources created by this template.

ServiceTag: Type: String Description: Exact name of the Service as defined in the service catalog. EnvironmentTag: Type: String Description: Used to distinguish between development, test, production,etc. environment types. AllowedValues: [dev, tst, prd, trn, stg, cfg, sup, rpt] Default: dev ContactNetidTag: Type: String Description: Used to identify the netid of the person most familiar with the usage of the resource. Default: szgilbert AccountNumberTag: Type: String Description: Identifies the financial system account number. TicketNumberTag: Type: String Description: Used to identify the Jira, Cherwell, or other ticketing system ticket number to link to more information about the need for the resource. Conditions: IsPublic: !Equals [!Ref PublicOrPrivate, Public ] Resources: InstanceSG: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'Allow traffic to Confluence' VpcId: !Ref VPC SecurityGroupIngress: - SourceSecurityGroupId: !Ref LBSecurityGroup IpProtocol: "tcp" FromPort: "80" ToPort: "80" - SourceSecurityGroupId: !Ref LBSecurityGroup IpProtocol: "tcp" FromPort: "8888" ToPort: "8888" - CidrIp: 150.135.112.96/27 # EntApp VPN IpProtocol: "tcp" FromPort: "22" ToPort: "22" - CidrIp: 150.135.112.64/27 # InfraDev VPN IpProtocol: "tcp" FromPort: "22" ToPort: "22" - CidrIp: 128.196.135.64/26 # CC 317 IpProtocol: "tcp" FromPort: "22" ToPort: "22" EFSIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-efs-sg" IpProtocol: tcp FromPort: '2049' ToPort: '2049' SourceSecurityGroupId: !Ref InstanceSG DBIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: Fn::ImportValue: !Sub "${ConfluenceRDSStack}-dbsecuritygroup" IpProtocol: tcp FromPort: '3306' ToPort: '3306' SourceSecurityGroupId: !Ref InstanceSG EC2Role: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: s3-access PolicyDocument: Statement: - Effect: Allow Action: - 's3:*' Resource: !Sub - "arn:aws:s3:::${S3Bucket}*" - S3Bucket: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-confluencebucket" - PolicyName: logs-access PolicyDocument: Statement: - Effect: Allow Action: - 'logs:CreateLogStream' - 'logs:PutLogEvents' Resource: '*' EC2InstanceProfile: Type: 'AWS::IAM::InstanceProfile' Properties: Path: / Roles: - !Ref EC2Role ConfluenceInstance: Type: "AWS::EC2::Instance" Metadata: AWS::CloudFormation::Authentication: rolebased: type: "S3" buckets: - Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-confluencebucket" roleName: !Ref EC2Role AWS::CloudFormation::Init: configSets: bootStrap: - "configureUser" - "downloadMedia" - "installMedia" - "configureServer" - "configureAccess" - "uninstallJava" - "configureService" - "installMysql" configureUser: groups: confluenceadm: {} users: confluence: groups: - confluenceadm homeDir: /opt/confluence downloadMedia: files: /tmp/confluence.tgz: mode: 644 owner: confluence group: confluenceadm source: !Sub - "https://s3-${AWS::Region}.amazonaws.com/${S3Bucket}/installers/${InstallerFile}" - S3Bucket: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-confluencebucket" installMedia: packages: yum: nginx: [] commands: 01ensureDirectory: command: "mkdir -p /opt/confluence" 02extractConfluence: command: "cd /tmp; tar -zxf /tmp/confluence.tgz" 03moveConfluence: command: "mv /tmp/current-confl /opt/confluence/" configureServer: files: /etc/nginx/nginx.conf: mode: 775 owner: root content: | user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /var/run/nginx.pid; include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { 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; tcp_nodelay on; client_max_body_size 300M; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; include /etc/nginx/conf.d/*.conf; } /etc/nginx/conf.d/confluence.conf: mode: 775 owner: root content: | server { listen 80; location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_connect_timeout 600; proxy_send_timeout 600; proxy_read_timeout 600; send_timeout 600; } } server { listen *:8888 default_server; listen [::]:8888 default_server; return 301 https://$host$request_uri; } /etc/cron.d/confluence.backup: mode: 644 owner: root group: root content: !Sub - | 12 23 * * * root aws s3 sync --sse AES256 /efs/confluence/${ConfluenceEnvironment} s3://${S3Bucket}/backups/${ConfluenceEnvironment} >/dev/null 2>&1 - S3Bucket: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-confluencebucket" /etc/init.d/confluence: mode: 775 owner: root group: confluenceadm content: | #!/bin/bash

confluence This shell script takes care of starting and stopping confluence

chkconfig: - 58 74 description: confluence.

### BEGIN INIT INFO

Provides: confluence Required-Start: $network $local_fs $remote_fs Required-Stop: $network $local_fs $remote_fs Short-Description: start and stop confluence Description: confluence

### END INIT INFO case "$1" in start) su - confluence -c '/opt/confluence/current-confl/bin/start-confluence.sh' ;; stop) su - confluence -c '/opt/confluence/current-confl/bin/stop-confluence.sh' ;; status) ps aux | grep confluence ;; restart|force-reload) su - confluence -c '/opt/confluence/current-confl/bin/stop-confluence.sh' su - confluence -c '/opt/confluence/current-confl/bin/start-confluence.sh' ;; try-restart|condrestart) exit 3 ;; reload) exit 3 ;; *) echo $"Usage: $0 {start|stop|status|restart|try-restart|force-reload}" exit 2 esac /opt/confluence/current-confl/confluence/WEB-INF/classes/confluence-init.properties: mode: 644 owner: confluence group: confluenceadm content: !Sub | confluence.home=/efs/confluence/${ConfluenceEnvironment} /opt/confluence/current-confl/conf/server.xml: mode: 644 owner: confluence group: confluenceadm content: !Sub | <Server port="8000" shutdown="SHUTDOWN" debug="0"> <Service name="Tomcat-Standalone"> <Connector port="8080" maxHttpHeaderSize="8192" maxThreads="75" minSpareThreads="25" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" proxyName="${ServiceURL}" proxyPort="443" scheme="https" secure="true" relaxedQueryChars="|,[,],{,},*,^" relaxedPathChars="|,[,],{,},*,^" /> <Engine name="Standalone" defaultHost="localhost" debug="0"> <Host name="localhost" debug="0" appBase="webapps" unpackWARs="true" autoDeploy="false" startStopThreads="4"> <Context path="" docBase="../confluence" debug="0" reloadable="false" useHttpOnly="true"> <Manager pathname=""/> <Valve className="org.apache.catalina.valves.StuckThreadDetectionValve" threshold="60"/> </Context> </Host> </Engine> </Service> </Server> /opt/confluence/current-confl/confluence/WEB-INF/web.xml: mode: 644 owner: confluence group: confluenceadm source: !Sub - "https://s3-${AWS::Region}.amazonaws.com/${S3Bucket}/web.xml" - S3Bucket: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-confluencebucket" /opt/confluence/current-confl/confluence/WEB-INF/lib/mysql.jar: mode: 644 owner: confluence group: confluenceadm source: !Sub - "https://s3-${AWS::Region}.amazonaws.com/${S3Bucket}/mysql/mysql-connector-java-5.1.40-bin.jar" - S3Bucket: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-confluencebucket" /opt/confluence/current-confl/confluence/WEB-INF/lib/duo.jar: mode: 644 owner: confluence group: confluenceadm source: !Sub - "https://s3-${AWS::Region}.amazonaws.com/${S3Bucket}/duo/duo.jar" - S3Bucket: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-confluencebucket" /opt/confluence/current-confl/confluence/WEB-INF/lib/duo-client.jar: mode: 644 owner: confluence group: confluenceadm source: !Sub - "https://s3-${AWS::Region}.amazonaws.com/${S3Bucket}/duo/duo-client-0.2.1.jar" - S3Bucket: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-confluencebucket" /opt/confluence/current-confl/confluence/WEB-INF/lib/duo-filter.jar: mode: 644 owner: confluence group: confluenceadm source: !Sub - "https://s3-${AWS::Region}.amazonaws.com/${S3Bucket}/duo/duo-filter-1.3.5-SNAPSHOT.jar" - S3Bucket: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-confluencebucket" configureAccess: commands: 01setPerms: command: "chown -R confluence /opt/confluence && chmod -R u=rwx,go-rwx /opt/confluence" 02setupHome: command: "mkdir -p /var/confluence && chown -R confluence /var/confluence && chmod -R u=rwx,go-rwx /var/confluence" 03setupShell: command: "/usr/bin/chsh -s /bin/bash confluence" uninstallJava: commands: 01remove17: command: "yum remove -y java-1.7.0-openjdk" configureService: commands: completeInstallation: command: "/opt/confluence/current-confl/bin/version.sh > /var/log/confluenceInstallation.log" installMysql: commands: completeInstallation: command: "yum -y install mysql" services: sysvinit: nginx: enabled: "true" ensureRunning: "true" commands: - completeInstallation confluence: enabled: "true" ensureRunning: "true" commands: - completeInstallation CreationPolicy: ResourceSignal: Timeout: PT20M Properties: Tags: - Key: Name Value: !Ref AWS::StackName - Key: service Value: !Ref ServiceTag - Key: environment Value: !Ref EnvironmentTag - Key: contactnetid Value: !Ref ContactNetidTag - Key: accountnumber Value: !Ref AccountNumberTag - Key: ticketnumber Value: !Ref TicketNumberTag BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: VolumeSize: 150 InstanceType: !Ref InstanceType IamInstanceProfile: !Ref EC2InstanceProfile KeyName : !Ref KeyName ImageId : !Ref AmazonLinuxAmi UserData : Fn::Base64: !Sub - | #!/bin/bash -e yum update -y mkdir -p /efs/confluence #mount -t nfs4 -o vers=4.1 ${efsid}.efs.${AWS::Region}.amazonaws.com:/ /efs/confluence echo "${efsid}.efs.${AWS::Region}.amazonaws.com:/ /efs/confluence nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0" >> /etc/fstab mount -a -t nfs4

Set the Time Zone Need to escape the / in America/Phoenix

sed -i 's/ZONE="UTC"/ZONE="America\/Phoenix"/' /etc/sysconfig/clock ln -sf /usr/share/zoneinfo/America/Phoenix /etc/localtime #Ask CFN-INIT to install the configs listed in the bootStrap configset /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --configsets bootStrap --resource ConfluenceInstance --region ${AWS::Region} #Signal the result to the CF service /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ConfluenceInstance --region ${AWS::Region} chown -R confluence:confluence /efs/confluence

Reboot to make sure the Time Zone is picked up by everything

reboot - efsid: Fn::ImportValue: !Sub "${ConfluenceFoundationStack}-fs-id" SecurityGroupIds: - !Ref InstanceSG SubnetId: !Ref InstanceSubnet loadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: !If [IsPublic, internet-facing, internal] Subnets: - Ref: LBSubnetA - Ref: LBSubnetB LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '50' SecurityGroups: - Ref: LBSecurityGroup Tags: - Key: Name Value: !Sub "${AWS::StackName}-LoadBalancer" - Key: service Value: !Ref ServiceTag - Key: environment Value: !Ref EnvironmentTag - Key: contactnetid Value: !Ref ContactNetidTag - Key: accountnumber Value: !Ref AccountNumberTag - Key: ticketnumber Value: !Ref TicketNumberTag LBSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'Allow traffic to Confluence load balancer' VpcId: !Ref VPC SecurityGroupIngress: - CidrIp: 0.0.0.0/0 IpProtocol: "tcp" FromPort: "80" ToPort: "80" - CidrIp: 0.0.0.0/0 IpProtocol: "tcp" FromPort: "443" ToPort: "443" ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 60 UnhealthyThresholdCount: 10 HealthCheckPath: / Name: !Sub "${AWS::StackName}-tg" Port: 80 Protocol: HTTP VpcId: Ref: VPC Targets: - Id: !Ref ConfluenceInstance Port: 80 ALBListener443: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: Ref: ALBTargetGroup LoadBalancerArn: Ref: loadBalancer Port: 443 Protocol: HTTPS Certificates: - CertificateArn: !Ref SSLCertificatARN ALBRedirectTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 60 UnhealthyThresholdCount: 10 HealthCheckPath: / Name: !Sub "${AWS::StackName}-redirect-tg" Port: 80 Protocol: HTTP VpcId: Ref: VPC Targets: - Id: !Ref ConfluenceInstance Port: 8888 ALBListener80: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: Ref: ALBRedirectTargetGroup LoadBalancerArn: Ref: loadBalancer Port: 80 Protocol: HTTP EnvDnsRecord: Type: AWS::Route53::RecordSet Properties: HostedZoneName: !Sub "${HostedZoneName}." Name: !Sub "confluence-${ConfluenceEnvironment}.${HostedZoneName}." Type: "CNAME" TTL: "200" ResourceRecords: - !GetAtt loadBalancer.DNSName Outputs: ConfluenceEndpoint: Description: The endpoint where Confluence will become accessible on the desired service port Value: !Sub "https://confluence-${ConfluenceEnvironment}.${HostedZoneName}"