├── .gitignore
├── LICENSE
├── NOTICE
├── README.md
├── docs
└── architecture.png
├── examples
├── jenkins-master-ami
│ ├── README.md
│ ├── install_jenkins
│ └── jenkins.json
└── jenkins-slave-ami
│ ├── README.md
│ ├── jenkins-slave-service.sh
│ ├── jenkins-slave.conf
│ └── jenkins.json
├── main.tf
├── modules
├── jenkins-alb-security-group
│ ├── main.tf
│ ├── output.tf
│ └── variables.tf
├── jenkins-alb
│ ├── main.tf
│ ├── output.tf
│ └── variables.tf
├── jenkins-master
│ ├── main.tf
│ ├── outputs.tf
│ ├── setup.tpl
│ └── variables.tf
├── jenkins-security-group-rules
│ ├── master.tf
│ ├── outputs.tf
│ └── variables.tf
└── jenkins-slave
│ ├── main.tf
│ ├── outputs.tf
│ ├── setup.tpl
│ └── variables.tf
├── outputs.tf
└── variables.tf
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .terraform/
3 | terraform.tfstate*
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | terraform-aws-jenkins
2 | Copyright 2017 InfogroupNW, Inc.
3 |
4 | This product includes software developed at InfogroupNW (http://www.ignw.io/).
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Jenkins AWS Module
2 |
3 | This repo contains a Module for how to deploy a [Jenkins](https://jenkins.io/) cluster on
4 | [AWS](https://aws.amazon.com/) using [Terraform](https://www.terraform.io/). Jenkins is a distributed automation server, generally associated with [Continuous Integration (CI)](https://en.wikipedia.org/wiki/Continuous_integration) and [Continuous Delivery (CD)](https://en.wikipedia.org/wiki/Continuous_delivery). A Jenkins cluster typically involves one
5 | or more [master](https://wiki.jenkins.io/display/JENKINS/Distributed+builds) instance(s) coupled with one or more [slave](https://wiki.jenkins.io/display/JENKINS/Distributed+builds) instance(s):
6 |
7 | 
8 |
9 |
10 | ## How to use this Module
11 |
12 | Each Module has the following folder structure:
13 |
14 | * [root](https://github.com/ignw/terraform-aws-jenkins/tree/master): This folder shows an example of Terraform code
15 | that uses the [jenkins-master](https://github.com/ignw/terraform-aws-jenkins/tree/master/modules/jenkins-master) and
16 | [jenkins-slave](https://github.com/ignw/terraform-aws-jenkins/tree/master/modules/jenkins-slave) module(s) to
17 | deploy a [Jenkins](https://www.jenkins.io/) cluster in [AWS](https://aws.amazon.com/).
18 | * [modules](https://github.com/ignw/terraform-aws-jenkins/tree/master/modules): This folder contains the reusable code for this Module, broken down into one or more modules.
19 | * [examples](https://github.com/ignw/terraform-aws-jenkins/tree/master/examples): This folder contains examples of how to use the modules.
20 | * [test](https://github.com/ignw/terraform-aws-jenkins/tree/master/test): Automated tests for the modules and examples.
21 |
22 | To deploy Jenkins servers using this Module:
23 |
24 | 1. Create a Jankins Master AMI using a Packer template installs jenkins and all of the required dependencies.
25 | Here is an [example Packer template](https://github.com/ignw/terraform-aws-jenkins/tree/master/examples/jenkins-ami#quick-start).
26 |
27 | If you are just experimenting with this Module, you may find it more convenient to use one of our official public AMIs:
28 | - [Latest Master AMIs (Amazon Linux)](https://github.com/ignw/terraform-aws-jenkins/tree/master/_docs/amazon-linux-ami-list.md).
29 | - [Latest Slave AMIs (Amazon Linux)](https://github.com/ignw/terraform-aws-jenkins/tree/master/_docs/amazon-linux-ami-list.md).
30 |
31 | **WARNING! Do NOT use these AMIs in your production setup. In production, you should build your own AMIs in your own
32 | AWS account.**
33 |
34 | 2. Deploy those AMIs to your AWS region using the Terraform [jenkins-master module](https://github.com/ignw/terraform-aws-jenkins/tree/master/modules/jenkins-master)
35 | and execute the [jenkins-slave module](https://github.com/ignw/terraform-aws-jenkins/tree/master/modules/jenkins-slave) Here is [an example Terraform
36 | configuration](https://github.com/ignw/terraform-aws-jenkins/tree/master/MAIN.md#quick-start) to provision a Jenkins cluster.
37 |
38 | To deploy Jenkins clients using this Module:
39 |
40 | ```
41 | terraform init
42 |
43 | terraform plan --var "ssh_key_name=ignw_dev" \
44 | --var "ssh_key_path=~/.ssh/ignw_dev.pem" \
45 | --var "linux_slave_count=1" \
46 | --var aws_ssl_certificate_arn="arn:aws:acm:us-east-1:xxxxxxxxxxx" \
47 | --var dns_zone="example.com" \
48 | --var app_dns_name="jenkins.example.com" \
49 |
50 | terraform apply --var "ssh_key_name=ignw_dev" \
51 | --var "ssh_key_path=~/.ssh/ignw_dev.pem" \
52 | --var "linux_slave_count=1" \
53 | --var aws_ssl_certificate_arn="arn:aws:acm:us-east-1:xxxxxxxxxxx" \
54 | --var dns_zone="example.com" \
55 | --var app_dns_name="jenkins.example.com" \
56 |
57 | ```
58 | Argument | Description
59 | --- | ---
60 | name | The name to be used on all instances as a prefix
61 | ssh_key_name | AWS SSH Key Pair name
62 | ssh_key_path | Path to AWS SSH Key Pair private key pair used for provisioning
63 | linux_slave_count | The number of Jenkins Linux Build Slaves to provision
64 | win_slave_count | The number of Jenkins Windows Build Slaves to provision
65 | instance_type_master | The instance type to be used on the master instance. Default: t2.micro
66 | instance_type_slave | The instance type to be used on the slave instance(s). Default: t2.micro
67 | setup_data | The script used to setup the Jenkins master instance and install plugins. Default: ./modules/jenkins-master/setup.tpl
68 | http_port | The port to use for HTTP traffic to Jenkins
69 | jnlp_port | The Port to use for Jenkins master to slave communication bewtween instances
70 | plugins | The list of plugins to pre-install on the master instance. Default: ["git", "xunit"]
71 | tags | A map of tags to add to all resources
72 | master_ami_id | ID of the AMI to use for master instance. Default: lookup latest IGNW master AMI
73 | linux_slave_ami_id | ID of the AMI to use for linux slave instance(s). Default: lookup latest IGNW linux slave AMI
74 | win_slave_ami_id | ID of the AMI to use for windows slave instance(s). Default: lookup latest IGNW windows slave AMI
75 | aws_ssl_certificate_arn | Amazon Resource Name for the certificate to be used on the load balancer for HTTPS
76 | dns_zone | DNS zone in AWS Route53 to use for the Application Load Balancer (ALB)
77 | app_dns_name | DNS name within the zone to dynamically point to the ALB
78 |
79 | ## What's a Module?
80 |
81 | A Module is a canonical, reusable, best-practices definition for how to run a single piece of infrastructure, such
82 | as a database or server cluster. Each Module is created using [Terraform](https://www.terraform.io/), and
83 | includes automated tests, examples, and documentation. It is maintained both by the open source community and
84 | companies that provide commercial support.
85 |
86 | Instead of figuring out the details of how to run a piece of infrastructure from scratch, you can reuse
87 | existing code that has been proven in production. And instead of maintaining all that infrastructure code yourself,
88 | you can leverage the work of the Module community to pick up infrastructure improvements through
89 | a version number bump.
90 |
91 |
92 |
93 | ## Who maintains this Module?
94 |
95 | This Module is maintained by [IGNW](http://www.ignw.io/). If you're looking for help or commercial
96 | support, send an email to [support@infogroupnw.com](mailto:support@infogroupnw.com?Subject=Jenkins%20Module).
97 | IGNW can help with:
98 |
99 | * Setup, customization, and support for this Module.
100 | * Modules for other types of infrastructure, such as VPCs, Docker clusters, databases, and continuous integration.
101 | * Modules that meet compliance requirements, such as FedRamp, HIPAA.
102 | * Consulting & Training on AWS, Azure, GCP, Terraform, and DevOps.
103 |
104 |
105 |
106 | ## Code included in this Module:
107 |
108 | * [jenkins-master](https://github.com/ignw/terraform-aws-jenkins/tree/master/modules/jenkins-master): The module includes Terraform code to deploy a Jenkins master on AWS and setup [plugins](https://plugins.jenkins.io).
109 |
110 | * [jenkins-slave](https://github.com/ignw/terraform-aws-jenkins/tree/master/modules/jenkins-slave): The module includes Terraform code to deploy a Jenkins [slave](https://wiki.jenkins.io/display/JENKINS/Distributed+builds) on AWS and connect it to it's [master](https://wiki.jenkins.io/display/JENKINS/Distributed+builds).
111 |
112 | * [jenkins-security-group-rules](https://github.com/ignw/terraform-aws-jenkins/tree/master/modules/jenkins-security-group-rules): Defines the security group rules used by a
113 | Jenkins cluster to control the traffic that is allowed to go in and out of the cluster.
114 |
115 |
116 | ## How is this Module versioned?
117 |
118 | This Module follows the principles of [Semantic Versioning](http://semver.org/). You can find each new release,
119 | along with the changelog, in the [Releases Page](../../releases).
120 |
121 | During initial development, the major version will be 0 (e.g., `0.x.y`), which indicates the code does not yet have a
122 | stable API. Once we hit `1.0.0`, we will make every effort to maintain a backwards compatible API and use the MAJOR,
123 | MINOR, and PATCH versions on each release to indicate any incompatibilities.
124 |
125 |
126 |
127 | ## License
128 |
129 | This code is released under the Apache 2.0 License. Please see [LICENSE](https://github.com/ignw/terraform-aws-jenkins/tree/master/LICENSE) and [NOTICE](https://github.com/ignw/terraform-aws-jenkins/tree/master/NOTICE) for more
130 | details.
131 |
132 | Copyright © 2017 InfogroupNW, Inc.
--------------------------------------------------------------------------------
/docs/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IGNW/terraform-aws-jenkins/75b200b9f3674cc108a1894a45f78de97cfe0ed2/docs/architecture.png
--------------------------------------------------------------------------------
/examples/jenkins-master-ami/README.md:
--------------------------------------------------------------------------------
1 | # Jenkins Master AMI
2 |
3 | This folder shows an example Jenkins master server build using a packer template to generate an AMI.
4 |
5 | OS: _Amazon Linux_
6 |
7 | These AMIs will have [Jenkins](https://www.jenkins.io/) installed and configured to automatically run the Jenkins daemon service. You would need to tailor this environment
8 | to include your build tools or run all builds on slave instance(s).
9 |
10 | Installed
11 | * Java 1.8 Open JDK
12 | * Git Tools
13 | * AWS CLI Tools
14 | * Apache Maven
15 | * Jenkins
16 |
17 | ## Quick start
18 |
19 | To build the Jenkins Master AMI:
20 |
21 | 1. `git clone` this repo to your computer.
22 | 1. Install [Packer](https://www.packer.io/).
23 | 1. Configure your AWS credentials using one of the [options supported by the AWS
24 | SDK](http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html). Usually, the easiest option is to
25 | set the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
26 | 1. Update the `variables` section of the `jenkins.json` Packer template to configure the AWS region and Jenkins version you wish to use.
27 | 1. Run `packer build jenkins.json`.
28 |
29 | When the build finishes, it will output the IDs of the new AMIs. To see how to deploy one of these AMIs, check out the
30 | [jenkins example](https://github.com/ignw/terraform-aws-jenkins/tree/master/MAIN.md).
--------------------------------------------------------------------------------
/examples/jenkins-master-ami/install_jenkins:
--------------------------------------------------------------------------------
1 | sudo yum -y update
2 |
3 | sudo yum install -y java-1.8.0-openjdk.x86_64
4 |
5 | sudo /usr/sbin/alternatives --set java /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java
6 |
7 | sudo /usr/sbin/alternatives --set javac /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/javac
8 |
9 | sudo yum remove -y java-1.7*
10 |
11 | # install core reqs plus nginx for ssl termination
12 | sudo yum install -y git nginx aws-cli
13 | sudo update-alternatives --config java
14 |
15 | # install maven
16 | sudo wget http://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-maven.repo -O /etc/yum.repos.d/epel-apache-maven.repo
17 | sudo sed -i s/\$releasever/6/g /etc/yum.repos.d/epel-apache-maven.repo
18 | sudo yum install -y apache-maven
19 | #mvn –v
20 |
21 | # install xmlstarlet used for XML config manipulation
22 | sudo yum install -y xmlstarlet
23 |
24 | # install jenkins
25 | sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
26 | sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
27 |
28 | # todo: parameterize version
29 | sudo yum install -y jenkins
--------------------------------------------------------------------------------
/examples/jenkins-master-ami/jenkins.json:
--------------------------------------------------------------------------------
1 | {
2 | "min_packer_version": "0.12.0",
3 | "variables": {
4 | "aws_region": "us-east-1",
5 | "jenkins_version": "2.8"
6 | },
7 | "builders": [{
8 | "name": "amazon-linux-ami",
9 | "ami_name": "jenkins-amazon-linux-{{isotime | clean_ami_name}}",
10 | "ami_description": "An Amazon Linux AMI that has Jenkins installed.",
11 | "instance_type": "t2.micro",
12 | "region": "{{user `aws_region`}}",
13 | "type": "amazon-ebs",
14 | "source_ami_filter": {
15 | "filters": {
16 | "virtualization-type": "hvm",
17 | "architecture": "x86_64",
18 | "name": "*amzn-ami-hvm-*",
19 | "block-device-mapping.volume-type": "gp2",
20 | "root-device-type": "ebs"
21 | },
22 | "owners": ["amazon"],
23 | "most_recent": true
24 | },
25 | "ssh_username": "ec2-user"
26 | }],
27 | "provisioners": [{
28 | "type": "shell",
29 | "script": "./install_jenkins",
30 | "pause_before": "30s"
31 | }]
32 | }
--------------------------------------------------------------------------------
/examples/jenkins-slave-ami/README.md:
--------------------------------------------------------------------------------
1 | # Jenkins Slave AMI
2 |
3 | This folder shows an example Jenkins master server build using a packer template to generate an AMI.
4 |
5 | OS: _Amazon Linux_
6 |
7 | These AMIs will have [Jenkins](https://www.jenkins.io/) installed and configured to automatically run the Jenkins daemon service. You would need to tailor this environment
8 | to include your build tools or run all builds on slave instance(s).
9 |
10 | Installed
11 | * Java 1.8 Open JDK
12 | * Jenkins Slave JAR
13 |
14 | ## Quick start
15 |
16 | To build the Jenkins Slave AMI:
17 |
18 | 1. `git clone` this repo to your computer.
19 | 1. Install [Packer](https://www.packer.io/).
20 | 1. Configure your AWS credentials using one of the [options supported by the AWS
21 | SDK](http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html). Usually, the easiest option is to
22 | set the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
23 | 1. Update the `variables` section of the `jenkins.json` Packer template to configure the AWS region and Jenkins version you wish to use.
24 | 1. Run `packer build jenkins.json`.
25 |
26 | When the build finishes, it will output the IDs of the new AMIs. To see how to deploy one of these AMIs, check out the
27 | [jenkins example](https://github.com/ignw/terraform-aws-jenkins/tree/master/MAIN.md).
--------------------------------------------------------------------------------
/examples/jenkins-slave-ami/jenkins-slave-service.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | ### BEGIN INIT INFO
3 | # Provides:
4 | # Required-Start: $remote_fs $syslog
5 | # Required-Stop: $remote_fs $syslog
6 | # Default-Start: 2 3 4 5
7 | # Default-Stop: 0 1 6
8 | # Short-Description: Start Jenkins slave daemon at boot time
9 | # Description: Jenkins Build Slave for running Linux builds
10 | ### END INIT INFO
11 |
12 | name=`basename $0`
13 | pid_file="/var/run/$name.pid"
14 | stdout_log="/var/log/$name.log"
15 | stderr_log="/var/log/$name.err"
16 |
17 | user="jenkins"
18 | dir="/home/$user/$name"
19 |
20 | # load Jenkins config
21 | . /home/jenkins/jenkins-slave/config
22 |
23 | cmd="java -jar slave.jar -jnlpUrl $JENKINS_URL/computer/$JENKINS_SLAVE/slave-agent.jnlp -secret $JENKINS_SECRET"
24 |
25 | get_pid() {
26 | cat "$pid_file"
27 | }
28 |
29 | is_running() {
30 | [ -f "$pid_file" ] && ps -p `get_pid` > /dev/null 2>&1
31 | }
32 |
33 | case "$1" in
34 | start)
35 | if is_running; then
36 | echo "Already started"
37 | else
38 | echo "Starting $name"
39 | cd $dir
40 | if [ -z "$user" ]; then
41 | sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
42 | else
43 | sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
44 | fi
45 | echo $! > "$pid_file"
46 | if ! is_running; then
47 | echo "Unable to start, see $stdout_log and $stderr_log"
48 | exit 1
49 | fi
50 | fi
51 | ;;
52 | stop)
53 | if is_running; then
54 | echo -n "Stopping $name.."
55 | kill `get_pid`
56 | for i in 1 2 3 4 5 6 7 8 9 10
57 | # for i in `seq 10`
58 | do
59 | if ! is_running; then
60 | break
61 | fi
62 |
63 | echo -n "."
64 | sleep 1
65 | done
66 | echo
67 |
68 | if is_running; then
69 | echo "Not stopped; may still be shutting down or shutdown may have failed"
70 | exit 1
71 | else
72 | echo "Stopped"
73 | if [ -f "$pid_file" ]; then
74 | rm "$pid_file"
75 | fi
76 | fi
77 | else
78 | echo "Not running"
79 | fi
80 | ;;
81 | restart)
82 | $0 stop
83 | if is_running; then
84 | echo "Unable to stop, will not attempt to start"
85 | exit 1
86 | fi
87 | $0 start
88 | ;;
89 | status)
90 | if is_running; then
91 | echo "Running"
92 | else
93 | echo "Stopped"
94 | exit 1
95 | fi
96 | ;;
97 | *)
98 | echo "Usage: $0 {start|stop|restart|status}"
99 | exit 1
100 | ;;
101 | esac
102 |
103 | exit 0
--------------------------------------------------------------------------------
/examples/jenkins-slave-ami/jenkins-slave.conf:
--------------------------------------------------------------------------------
1 | JENKINS_URL=
2 | JENKINS_SLAVE=
3 | JENKINS_SECRET=
--------------------------------------------------------------------------------
/examples/jenkins-slave-ami/jenkins.json:
--------------------------------------------------------------------------------
1 | {
2 | "min_packer_version": "0.12.0",
3 | "variables": {
4 | "aws_region": "us-east-1",
5 | "jenkins_version": "2.8"
6 | },
7 | "builders": [{
8 | "name": "amazon-linux-ami",
9 | "ami_name": "jenkins-slave-amazon-linux-{{isotime | clean_ami_name}}",
10 | "ami_description": "An Amazon Linux AMI that has Jenkins Slave dependencies installed.",
11 | "instance_type": "t2.micro",
12 | "region": "{{user `aws_region`}}",
13 | "type": "amazon-ebs",
14 | "source_ami_filter": {
15 | "filters": {
16 | "virtualization-type": "hvm",
17 | "architecture": "x86_64",
18 | "name": "*amzn-ami-hvm-*",
19 | "block-device-mapping.volume-type": "gp2",
20 | "root-device-type": "ebs"
21 | },
22 | "owners": ["amazon"],
23 | "most_recent": true
24 | },
25 | "ssh_username": "ec2-user"
26 | }],
27 | "provisioners": [{
28 | "type": "shell",
29 | "inline" : [
30 | "sudo yum -y update",
31 | "sudo yum install -y java-1.8.0-openjdk.x86_64",
32 | "sudo yum remove -y java-1.7*",
33 | "sudo /usr/sbin/alternatives --set java /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java"
34 | ]
35 | }, {
36 | "type": "shell",
37 | "inline" : [
38 | "sudo useradd --home-dir /home/jenkins --create-home --shell /bin/bash jenkins",
39 | "echo 'jenkins' | sudo passwd 'jenkins' --stdin --force",
40 | "sudo mkdir /home/jenkins/jenkins-slave",
41 | "wget https://repo.jenkins-ci.org/public/org/jenkins-ci/main/remoting/{{user `jenkins_version`}}/remoting-{{user `jenkins_version`}}.jar",
42 | "sudo mv remoting-{{user `jenkins_version`}}.jar /home/jenkins/jenkins-slave/slave.jar"
43 | ]
44 | }, {
45 | "type": "file",
46 | "source": "jenkins-slave.conf",
47 | "destination": "/tmp/jenkins-slave.conf"
48 | }, {
49 | "type": "file",
50 | "source": "jenkins-slave-service.sh",
51 | "destination": "/tmp/jenkins-slave-service.sh"
52 | }, {
53 | "type": "shell",
54 | "inline" : [
55 | "sudo mv /tmp/jenkins-slave.conf /home/jenkins/jenkins-slave/config",
56 | "sudo chown -R jenkins:jenkins /home/jenkins",
57 | "sudo mv /tmp/jenkins-slave-service.sh /etc/init.d/jenkins-slave",
58 | "sudo chmod +x /etc/init.d/jenkins-slave",
59 | "sudo chkconfig --add jenkins-slave"
60 | ]
61 | }]
62 | }
--------------------------------------------------------------------------------
/main.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = "${var.aws_region}"
3 | }
4 |
5 | data "aws_ami" "jenkins" {
6 | most_recent = true
7 |
8 | # If we change the AWS Account in which test are run, update this value.
9 | owners = ["312506926764"]
10 |
11 | filter {
12 | name = "virtualization-type"
13 | values = ["hvm"]
14 | }
15 |
16 | filter {
17 | name = "is-public"
18 | values = ["false"] // flip to public when ready for release
19 | }
20 |
21 | filter {
22 | name = "name"
23 | values = ["jenkins-amazon-linux-*"]
24 | }
25 | }
26 |
27 | # Jenkins Master Instance
28 | module "jenkins-master" {
29 | source = "./modules/jenkins-master"
30 |
31 | vpc_id = "${data.aws_vpc.default.id}"
32 |
33 | name = "${var.name == "" ? "jenkins-master" : join("-", list(var.name, "jenkins-master"))}"
34 | alb_prefix = "${var.name == "" ? "jenkins" : join("-", list(var.name, "jenkins"))}"
35 | instance_type = "${var.instance_type_master}"
36 |
37 | ami_id = "${var.master_ami_id == "" ? data.aws_ami.jenkins.image_id : var.master_ami_id}"
38 | user_data = ""
39 | setup_data = "${data.template_file.setup_data_master.rendered}"
40 |
41 | http_port = "${var.http_port}"
42 | allowed_ssh_cidr_blocks = ["0.0.0.0/0"]
43 | allowed_inbound_cidr_blocks = ["0.0.0.0/0"]
44 | ssh_key_name = "${var.ssh_key_name}"
45 | ssh_key_path = "${var.ssh_key_path}"
46 |
47 | # Config used by the Application Load Balancer
48 | subnet_ids = "${data.aws_subnet_ids.default.ids}"
49 | aws_ssl_certificate_arn = "${var.aws_ssl_certificate_arn}"
50 | dns_zone = "${var.dns_zone}"
51 | app_dns_name = "${var.app_dns_name}"
52 | }
53 |
54 | data "template_file" "setup_data_master" {
55 | template = "${file("./modules/jenkins-master/setup.tpl")}"
56 |
57 | vars = {
58 | jnlp_port = "${var.jnlp_port}"
59 | plugins = "${join(" ", var.plugins)}"
60 | }
61 | }
62 |
63 | # Jenkins Linux Slave Instance(s)
64 | module "jenkins-linux-slave" {
65 | source = "./modules/jenkins-slave"
66 |
67 | count = "${var.linux_slave_count}"
68 |
69 | name = "${var.name == "" ? "jenkins-linux-slave" : join("-", list(var.name, "jenkins-linux-slave"))}"
70 | instance_type = "${var.instance_type_slave}"
71 |
72 | ami_id = "${var.linux_slave_ami_id}"
73 | jenkins_security_group_id = "${module.jenkins-master.jenkins_security_group_id}"
74 |
75 | jenkins_master_ip = "${module.jenkins-master.private_ip}"
76 | jenkins_master_port = "${var.http_port}"
77 |
78 | ssh_key_name = "${var.ssh_key_name}"
79 | ssh_key_path = "${var.ssh_key_path}"
80 | }
81 |
82 | data "aws_vpc" "default" {
83 | default = true
84 | }
85 |
86 | data "aws_subnet_ids" "default" {
87 | vpc_id = "${data.aws_vpc.default.id}"
88 | }
--------------------------------------------------------------------------------
/modules/jenkins-alb-security-group/main.tf:
--------------------------------------------------------------------------------
1 | #-------------------
2 | # LB security group
3 | #-------------------
4 | resource "aws_security_group" "lb_security_group" {
5 | name_prefix = "${var.name_prefix}"
6 | description = "Security group for the load balancer"
7 | vpc_id = "${var.vpc_id}"
8 |
9 | tags {
10 | Name = "${var.name_prefix}"
11 | }
12 | }
13 |
14 | # Allow HTTPS in from specific external subnets if public access is not enabled
15 | resource "aws_security_group_rule" "allow_lb_https_inbound" {
16 | type = "ingress"
17 | from_port = 443
18 | to_port = 443
19 | protocol = "tcp"
20 | cidr_blocks = ["${var.jenkins_private_ip}/32", "${var.allowed_inbound_cidr_blocks}"]
21 |
22 | security_group_id = "${aws_security_group.lb_security_group.id}"
23 | }
24 |
25 | resource "aws_security_group_rule" "allow_lb_outbound" {
26 | type = "egress"
27 | from_port = 0
28 | to_port = 0
29 | protocol = "-1"
30 | cidr_blocks = ["0.0.0.0/0"]
31 |
32 | security_group_id = "${aws_security_group.lb_security_group.id}"
33 | }
34 |
--------------------------------------------------------------------------------
/modules/jenkins-alb-security-group/output.tf:
--------------------------------------------------------------------------------
1 | output "lb_security_group_id" {
2 | value = "${aws_security_group.lb_security_group.id}"
3 | }
4 |
--------------------------------------------------------------------------------
/modules/jenkins-alb-security-group/variables.tf:
--------------------------------------------------------------------------------
1 | variable "vpc_id" {
2 | description = "The ID of the VPC"
3 | default = ""
4 | }
5 |
6 | variable "name_prefix" {
7 | description = "The prefix for the load balancer instance name"
8 | }
9 |
10 | variable "allowed_inbound_cidr_blocks" {
11 | description = "Networks to allow to connect to Jenkins"
12 | type = "list"
13 | }
14 |
15 | variable "jenkins_private_ip" {
16 | description = "Private IP address of the Jenkins instance"
17 | }
18 |
--------------------------------------------------------------------------------
/modules/jenkins-alb/main.tf:
--------------------------------------------------------------------------------
1 | # This module builds an Application Load balancer
2 |
3 | data "aws_instance" "jenkins" {
4 | instance_id = "${var.jenkins_instance_id}"
5 | }
6 |
7 | data "aws_subnet_ids" "default" {
8 | vpc_id = "${var.vpc_id}"
9 | }
10 |
11 | # Create the security group to control access to the load balancer
12 | module "lb-security-group" {
13 | source = "../jenkins-alb-security-group"
14 | name_prefix = "${var.name_prefix}-lb-sg"
15 | allowed_inbound_cidr_blocks = "${var.allowed_inbound_cidr_blocks}"
16 | jenkins_private_ip = "${data.aws_instance.jenkins.private_ip}"
17 | vpc_id = "${var.vpc_id}"
18 | }
19 |
20 | # Create the Application Load Balancer, attached to the given subnets
21 | resource "aws_lb" "alb" {
22 | name = "${var.name_prefix}-alb"
23 | security_groups = ["${module.lb-security-group.lb_security_group_id}"]
24 | subnets = ["${var.subnet_ids}"]
25 | }
26 |
27 | # Create a target group to send traffic to for JIRA
28 | resource "aws_lb_target_group" "alb_tg" {
29 | name = "${var.name_prefix}-alb-tg"
30 | port = "${var.http_port}"
31 | protocol = "HTTP"
32 | vpc_id = "${var.vpc_id}"
33 | }
34 |
35 | # Attach the JIRA EC2 instance to the target group
36 | resource "aws_lb_target_group_attachment" "tg_attach" {
37 | target_group_arn = "${aws_lb_target_group.alb_tg.arn}"
38 | target_id = "${var.jenkins_instance_id}"
39 | port = "${var.http_port}"
40 | }
41 |
42 | # Associate the listener resource to the load balancer, and configure SSL
43 | resource "aws_lb_listener" "lb-listener" {
44 | load_balancer_arn = "${aws_lb.alb.arn}"
45 | port = 443
46 | protocol = "HTTPS"
47 | ssl_policy = "ELBSecurityPolicy-2016-08"
48 | certificate_arn = "${var.aws_ssl_certificate_arn}"
49 |
50 | "default_action" {
51 | target_group_arn = "${aws_lb_target_group.alb_tg.arn}"
52 | type = "forward"
53 | }
54 | }
55 |
56 | # Update the DNS zone in AWS Route53 to point our domain name to this ALB
57 | data "aws_route53_zone" "app_dns_zone" {
58 | name = "${var.dns_zone}"
59 | private_zone = false
60 | }
61 |
62 | resource "aws_route53_record" "dns" {
63 | zone_id = "${data.aws_route53_zone.app_dns_zone.zone_id}"
64 | name = "${var.app_dns_name}"
65 | type = "A"
66 |
67 | alias {
68 | name = "${aws_lb.alb.dns_name}"
69 | zone_id = "${aws_lb.alb.zone_id}"
70 | evaluate_target_health = false
71 | }
72 | }
--------------------------------------------------------------------------------
/modules/jenkins-alb/output.tf:
--------------------------------------------------------------------------------
1 | output "lb_dns_name" {
2 | value = "${aws_lb.alb.dns_name}"
3 | }
4 |
--------------------------------------------------------------------------------
/modules/jenkins-alb/variables.tf:
--------------------------------------------------------------------------------
1 | variable "name_prefix" {
2 | description = "Name to be used on resources as prefix"
3 | default = ""
4 | }
5 |
6 | variable "vpc_id" {
7 | description = "The ID of the VPC"
8 | default = ""
9 | }
10 |
11 | variable "allowed_inbound_cidr_blocks" {
12 | description = "Networks to allow to connect to the load balancer"
13 | type = "list"
14 | }
15 |
16 | variable "http_port" {
17 | description = "HTTP port to access the application server behind the ALB"
18 | }
19 |
20 | variable "jenkins_instance_id" {
21 | description = "The ID of the Jenkins master instance"
22 | }
23 |
24 | variable "subnet_ids" {
25 | description = "Subnets for the load balancer listener to use"
26 | type = "list"
27 | }
28 |
29 | variable "aws_ssl_certificate_arn" {
30 | description = "Amazon Resource Name for the certificate to be used on the load balancer for HTTPS"
31 | }
32 |
33 | variable "dns_zone" {
34 | description = "DNS zone in AWS Route53 to use with the ALB"
35 | }
36 |
37 | variable "app_dns_name" {
38 | description = "DNS name within the zone to dynamically point to the ALB"
39 | }
40 |
--------------------------------------------------------------------------------
/modules/jenkins-master/main.tf:
--------------------------------------------------------------------------------
1 | # Launch EC2 instance for master
2 |
3 | // TODO: Add ELB for HTTP & HTTPS
4 | // TODO: Lockdown traffic and make instances private
5 | // TODO: Refactor security group code so Master has SSH, HTTP + JNLP and Slaves only have SSH, JNLP
6 |
7 | # Master ELB
8 | /*
9 | resource "aws_iam_server_certificate" "test_cert" {
10 | name_prefix = "example-cert"
11 | certificate_body = "${file("self-ca-cert.pem")}"
12 | private_key = "${file("test-key.pem")}"
13 |
14 | lifecycle {
15 | create_before_destroy = true
16 | }
17 | }
18 |
19 | resource "aws_elb" "ourapp" {
20 | name = "terraform-asg-deployment-example"
21 | availability_zones = ["us-west-2a"]
22 | cross_zone_load_balancing = true
23 |
24 | listener {
25 | instance_port = 8000
26 | instance_protocol = "http"
27 | lb_port = 443
28 | lb_protocol = "https"
29 | ssl_certificate_id = "${aws_iam_server_certificate.test_cert.arn}"
30 | }
31 |
32 | # The instances are registered automatically
33 | instances = ["${aws_instance.web.*.id}"]
34 | }
35 |
36 | */
37 |
38 | # Master Server
39 | resource "aws_instance" "ec2_jenkins_master" {
40 | count = 1
41 | ami = "${var.ami_id}"
42 | instance_type = "${var.instance_type}"
43 | user_data = "${var.user_data}"
44 | key_name = "${var.ssh_key_name}"
45 | monitoring = true
46 | vpc_security_group_ids = ["${module.security_group_rules.jenkins_security_group_id}"]
47 | tags = "${merge(map("Name", format("%s-%d", var.name, count.index+1)), map("Terraform", "true"), map("Environment", var.environment), var.tags)}"
48 |
49 | provisioner "file" {
50 | connection = {
51 | user = "ec2-user"
52 | private_key = "${file(var.ssh_key_path)}"
53 | }
54 | content = "${var.setup_data}"
55 | destination = "/tmp/setup.sh"
56 | }
57 |
58 | provisioner "remote-exec" {
59 | connection = {
60 | user = "ec2-user"
61 | private_key = "${file(var.ssh_key_path)}"
62 | }
63 | inline = [
64 | "chmod +x /tmp/setup.sh",
65 | "sudo /tmp/setup.sh"
66 | ]
67 | }
68 | }
69 |
70 | module "security_group_rules" {
71 | source = "../jenkins-security-group-rules"
72 |
73 | name = "${var.name}"
74 | allowed_inbound_cidr_blocks = ["${var.allowed_inbound_cidr_blocks}"]
75 | allowed_ssh_cidr_blocks = ["${var.allowed_ssh_cidr_blocks}"]
76 |
77 | http_port = "${var.http_port}"
78 | https_port = "${var.https_port}"
79 | jnlp_port = "${var.jnlp_port}"
80 | }
81 |
82 | # Add the application load balancer
83 | module "jenkins-alb" {
84 | source = "../jenkins-alb"
85 | name_prefix = "${var.alb_prefix}"
86 | vpc_id = "${var.vpc_id}"
87 | allowed_inbound_cidr_blocks = "${var.allowed_inbound_cidr_blocks}"
88 | http_port = "${var.http_port}"
89 | jenkins_instance_id = "${aws_instance.ec2_jenkins_master.id}"
90 | subnet_ids = "${var.subnet_ids}"
91 | aws_ssl_certificate_arn = "${var.aws_ssl_certificate_arn}"
92 | app_dns_name = "${var.app_dns_name}"
93 | dns_zone = "${var.dns_zone}"
94 | }
95 |
--------------------------------------------------------------------------------
/modules/jenkins-master/outputs.tf:
--------------------------------------------------------------------------------
1 | output "security_group_name" {
2 | value = "${module.security_group_rules.security_group_name}"
3 | }
4 |
5 | output "jenkins_security_group_id" {
6 | value = "${module.security_group_rules.jenkins_security_group_id}"
7 | }
8 |
9 | output "private_ip" {
10 | value = "${aws_instance.ec2_jenkins_master.private_ip}"
11 | }
12 |
13 | output "public_ip" {
14 | value = "${aws_instance.ec2_jenkins_master.public_ip}"
15 | }
--------------------------------------------------------------------------------
/modules/jenkins-master/setup.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e -x
3 | # This script is meant to be run in the User Data of each EC2 Instance while it's booting.
4 |
5 | function waitForJenkins() {
6 | echo "Waiting jenkins to launch on 8080..."
7 |
8 | while ! nc -z localhost 8080; do
9 | sleep 0.1 # wait for 1/10 of the second before check again
10 | done
11 |
12 | echo "Jenkins launched"
13 | }
14 |
15 | function waitForPasswordFile() {
16 | echo "Waiting jenkins to generate password..."
17 |
18 | while [ ! -f /var/lib/jenkins/secrets/initialAdminPassword ]; do
19 | sleep 2 # wait for 1/10 of the second before check again
20 | done
21 |
22 | echo "Password created"
23 | }
24 |
25 | sudo service jenkins start
26 | sudo chkconfig --add jenkins
27 |
28 | waitForJenkins
29 |
30 | # UPDATE PLUGIN LIST
31 | curl -L http://updates.jenkins-ci.org/update-center.json | sed '1d;$d' | curl -X POST -H 'Accept: application/json' -d @- http://localhost:8080/updateCenter/byId/default/postBack
32 |
33 | sleep 10
34 |
35 | waitForJenkins
36 |
37 | # INSTALL CLI
38 | sudo cp /var/cache/jenkins/war/WEB-INF/jenkins-cli.jar /var/lib/jenkins/jenkins-cli.jar
39 |
40 | waitForPasswordFile
41 |
42 | PASS=$(sudo bash -c "cat /var/lib/jenkins/secrets/initialAdminPassword")
43 |
44 | sleep 10
45 |
46 | # SET AGENT PORT
47 | xmlstarlet ed -u "//slaveAgentPort" -v "${jnlp_port}" /var/lib/jenkins/config.xml > /tmp/jenkins_config.xml
48 | sudo mv /tmp/jenkins_config.xml /var/lib/jenkins/config.xml
49 | sudo service jenkins restart
50 |
51 | waitForJenkins
52 |
53 | sleep 10
54 |
55 | # INSTALL PLUGINS
56 | sudo java -jar /var/lib/jenkins/jenkins-cli.jar -s http://localhost:8080 -auth admin:$PASS install-plugin ${plugins}
57 |
58 | # RESTART JENKINS TO ACTIVATE PLUGINS
59 | sudo java -jar /var/lib/jenkins/jenkins-cli.jar -s http://localhost:8080 -auth admin:$PASS restart
--------------------------------------------------------------------------------
/modules/jenkins-master/variables.tf:
--------------------------------------------------------------------------------
1 | variable "name" {
2 | description = "Name to be used for the Jenkins master instance"
3 | }
4 |
5 | variable "environment" {
6 | description = "The environement tag to add to Jenkins master instance",
7 | default = ""
8 | }
9 |
10 | variable "ami_id" {
11 | description = "The ID of the AMI to run in this Jenkins master instance"
12 | }
13 |
14 | variable "instance_type" {
15 | description = "Instance Type to use for Jenkins master"
16 | }
17 |
18 | variable "vpc_id" {
19 | description = "The ID of the VPC"
20 | default = ""
21 | }
22 |
23 | variable "subnet_ids" {
24 | description = "Subnets for the load balancer listener to use"
25 | type = "list"
26 | }
27 |
28 | variable "aws_ssl_certificate_arn" {
29 | description = "Amazon Resource Name for the certificate to be used on the load balancer for HTTPS"
30 | }
31 |
32 | variable "dns_zone" {
33 | description = "DNS zone in AWS Route53 to use with the ALB"
34 | }
35 |
36 | variable "app_dns_name" {
37 | description = "DNS name within the zone to dynamically point to the ALB"
38 | }
39 |
40 | variable "alb_prefix" {
41 | description = "Naming prefix for ALB-related resources"
42 | }
43 |
44 | variable "user_data" {
45 | description = "A User Data script to execute while the server is booting."
46 | }
47 |
48 | variable "setup_data" {
49 | description = "A User Data script to execute after server has booted to setup jenkins defaults."
50 | }
51 |
52 | variable "ssh_key_name" {
53 | description = "The name of an EC2 Key Pair that can be used to SSH to the EC2 Instances in this cluster. Set to an empty string to not associate a Key Pair."
54 | default = ""
55 | }
56 |
57 | variable "ssh_key_path" {
58 | description = "The path of an EC2 Key Pair that can be used to SSH to the EC2 Instances in this cluster. Used for provisioning."
59 | default = ""
60 | }
61 |
62 | variable "allowed_ssh_cidr_blocks" {
63 | description = "A list of CIDR-formatted IP address ranges from which the EC2 Instances will allow connections on SSH"
64 | type = "list"
65 | }
66 |
67 | variable "allowed_inbound_cidr_blocks" {
68 | description = "A list of CIDR-formatted IP address ranges from which the EC2 Instances will allow connections to Jenkins"
69 | type = "list"
70 | }
71 |
72 | variable "ssh_port" {
73 | description = "The port used for SSH connections"
74 | default = 22
75 | }
76 |
77 | variable "http_port" {
78 | description = "The port to use for HTTP traffic to Jenkins"
79 | default = 8080
80 | }
81 |
82 | variable "https_port" {
83 | description = "The port to use for HTTPS traffic to Jenkins"
84 | default = 443
85 | }
86 |
87 | variable "jnlp_port" {
88 | description = "The port to use for TCP traffic between Jenkins intances"
89 | default = 49187
90 | }
91 |
92 | variable "tags" {
93 | type = "map"
94 | description = "Supply tags you want added to all resources"
95 | default = {
96 | }
97 | }
--------------------------------------------------------------------------------
/modules/jenkins-security-group-rules/master.tf:
--------------------------------------------------------------------------------
1 | # create security group to allow ssh
2 | resource "aws_security_group" "jenkins_security_group" {
3 | name_prefix = "${var.name}"
4 | description = "Security group for the ${var.name}"
5 | vpc_id = "${var.vpc_id}"
6 | }
7 |
8 | resource "aws_security_group_rule" "allow_ssh_inbound" {
9 | type = "ingress"
10 | from_port = "${var.ssh_port}"
11 | to_port = "${var.ssh_port}"
12 | protocol = "tcp"
13 | cidr_blocks = ["${var.allowed_ssh_cidr_blocks}"]
14 |
15 | security_group_id = "${aws_security_group.jenkins_security_group.id}"
16 | }
17 |
18 | resource "aws_security_group_rule" "allow_all_outbound" {
19 | type = "egress"
20 | from_port = 0
21 | to_port = 0
22 | protocol = "-1"
23 | cidr_blocks = ["0.0.0.0/0"]
24 |
25 | security_group_id = "${aws_security_group.jenkins_security_group.id}"
26 | }
27 |
28 | resource "aws_security_group_rule" "allow_http_inbound" {
29 | type = "ingress"
30 | from_port = "${var.http_port}"
31 | to_port = "${var.http_port}"
32 | protocol = "tcp"
33 | cidr_blocks = ["${var.allowed_inbound_cidr_blocks}"]
34 |
35 | security_group_id = "${aws_security_group.jenkins_security_group.id}"
36 | }
37 |
38 | resource "aws_security_group_rule" "allow_https_inbound" {
39 | type = "ingress"
40 | from_port = "${var.https_port}"
41 | to_port = "${var.https_port}"
42 | protocol = "tcp"
43 | cidr_blocks = ["${var.allowed_inbound_cidr_blocks}"]
44 |
45 | security_group_id = "${aws_security_group.jenkins_security_group.id}"
46 | }
47 |
48 | resource "aws_security_group_rule" "allow_jnlp_inbound" {
49 | type = "ingress"
50 | from_port = "${var.jnlp_port}"
51 | to_port = "${var.jnlp_port}"
52 | protocol = "tcp"
53 | cidr_blocks = ["${var.allowed_inbound_cidr_blocks}"]
54 |
55 | security_group_id = "${aws_security_group.jenkins_security_group.id}"
56 | }
--------------------------------------------------------------------------------
/modules/jenkins-security-group-rules/outputs.tf:
--------------------------------------------------------------------------------
1 | # The Name of the security group to which we should add the Jenkins security group rules
2 | output "security_group_name" {
3 | value = "${aws_security_group.jenkins_security_group.name}"
4 | }
5 |
6 | # The ID of the security group to which we should add the Jenkins security group rules
7 | output "jenkins_security_group_id" {
8 | value = "${aws_security_group.jenkins_security_group.id}"
9 | }
--------------------------------------------------------------------------------
/modules/jenkins-security-group-rules/variables.tf:
--------------------------------------------------------------------------------
1 | variable "vpc_id" {
2 | description = "The ID of the VPC"
3 | default = ""
4 | }
5 |
6 | variable "name" {
7 | description = "The Name of the security group to which we should add the Jenkins security group rules"
8 | }
9 |
10 | variable "allowed_inbound_cidr_blocks" {
11 | description = "A list of CIDR-formatted IP address ranges from which the EC2 Instances will allow connections to Jenkins"
12 | type = "list"
13 | }
14 |
15 | variable "allowed_ssh_cidr_blocks" {
16 | description = "A list of CIDR-formatted IP address ranges from which the EC2 Instances will allow connections on SSH"
17 | type = "list"
18 | }
19 |
20 | variable "ssh_port" {
21 | description = "The port used for SSH connections"
22 | default = 22
23 | }
24 |
25 | variable "http_port" {
26 | description = "The port to use for HTTP traffic to Jenkins"
27 | default = 8080
28 | }
29 |
30 | variable "https_port" {
31 | description = "The port to use for HTTPS traffic to Jenkins"
32 | default = 443
33 | }
34 |
35 | variable "jnlp_port" {
36 | description = "The port to use for TCP traffic between Jenkins intances"
37 | default = 49187
38 | }
--------------------------------------------------------------------------------
/modules/jenkins-slave/main.tf:
--------------------------------------------------------------------------------
1 |
2 | locals {
3 | jenkins_master_url = "http://${var.jenkins_master_ip}:${var.jenkins_master_port}"
4 | }
5 |
6 | data "aws_ami" "jenkins_linux_slave" {
7 | most_recent = true
8 |
9 | # If we change the AWS Account in which test are run, update this value.
10 | owners = ["312506926764"]
11 |
12 | filter {
13 | name = "virtualization-type"
14 | values = ["hvm"]
15 | }
16 |
17 | filter {
18 | name = "is-public"
19 | values = ["false"] // flip to public when ready for release
20 | }
21 |
22 | filter {
23 | name = "name"
24 | values = ["jenkins-slave-amazon-linux-*"]
25 | }
26 | }
27 |
28 | # Jenkins Slaves
29 | resource "aws_instance" "ec2_jenkins_slave" {
30 | count = "${var.count}"
31 | ami = "${var.ami_id == "" ? data.aws_ami.jenkins_linux_slave.image_id : var.ami_id}"
32 | instance_type = "${var.instance_type}"
33 | key_name = "${var.ssh_key_name}"
34 | monitoring = true
35 | vpc_security_group_ids = ["${var.jenkins_security_group_id}"]
36 | tags = "${merge(map("Name", format("%s-%d", var.name, count.index+1)), map("Terraform", "true"), map("Environment", var.environment), var.tags)}"
37 |
38 | provisioner "file" {
39 | connection = {
40 | user = "ec2-user"
41 | private_key = "${file(var.ssh_key_path)}"
42 | }
43 | content = "${file(var.ssh_key_path)}"
44 | destination = "/tmp/key.pem"
45 | }
46 |
47 | # Download dependencies from Master
48 | provisioner "remote-exec" {
49 | connection = {
50 | user = "ec2-user"
51 | private_key = "${file(var.ssh_key_path)}"
52 | }
53 |
54 | inline = [
55 | "chmod 0600 /tmp/key.pem",
56 | "ssh -oStrictHostKeyChecking=no -i /tmp/key.pem ec2-user@${var.jenkins_master_ip} 'sudo cat /var/lib/jenkins/secrets/initialAdminPassword' > /tmp/secret",
57 | "wget -P /tmp ${local.jenkins_master_url}/jnlpJars/jenkins-cli.jar",
58 | "wget -P /tmp ${local.jenkins_master_url}/jnlpJars/slave.jar",
59 | "sudo mv /tmp/slave.jar /home/jenkins/jenkins-slave/"
60 | ]
61 | }
62 |
63 | provisioner "file" {
64 | connection = {
65 | user = "ec2-user"
66 | private_key = "${file(var.ssh_key_path)}"
67 | }
68 | content = "${data.template_file.bootstrap.rendered}"
69 | destination = "/tmp/bootstrap.sh"
70 | }
71 |
72 | # Register & Launch slave
73 | provisioner "remote-exec" {
74 | connection = {
75 | user = "ec2-user"
76 | private_key = "${file(var.ssh_key_path)}"
77 | }
78 |
79 | inline = [
80 | "sudo chmod +x /tmp/bootstrap.sh",
81 | "/tmp/bootstrap.sh ${self.tags["Name"]}"
82 | ]
83 | }
84 |
85 | # Cleanup node registration
86 | # Currenlty unable to clean-up Jenkins node meta due to TF issue: https://github.com/hashicorp/terraform/issues/13549
87 | /*
88 | provisioner "remote-exec" {
89 | when = "destroy"
90 |
91 | connection = {
92 | host = "${self.private_ip}"
93 | user = "ec2-user"
94 | private_key = "${file(var.ssh_key_path)}"
95 | }
96 |
97 | inline = [
98 | "sudo service jenkins-slave stop",
99 | "sudo java -jar /tmp/jenkins-cli.jar -auth admin:$(
8 | $1
9 |
10 | /home/jenkins
11 | 2
12 | NORMAL
13 |
14 |
15 | $1
16 | 22
17 | admin
18 |
19 |
20 |
21 | admin
22 |
23 | EOF
24 |
25 |
26 | export TOKEN=$(curl --user "admin:$PASS" -s ${jenkins_master_url}/crumbIssuer/api/json | python -c 'import sys,json;j=json.load(sys.stdin);print j["crumbRequestField"] + "=" + j["crumb"]')
27 |
28 | cat > /tmp/secret.groovy </dev/null <