Jenkins CI Server
Overview
This service contains code to deploy Jenkins CI Server on AWS.
Jenkins architecture
Features
- Deploy Jenkins CI Server
- Run Jenkins in an Auto Scaling Group for high availability
- Store the
JENKINS_HOME
directory in an EBS Volume - Take nightly snapshots of the EBS Volume using the
ec2-backup
scheduled Lambda function - Run an ALB in front of Jenkins so it’s not accessible directly to users
- Configure DNS in Route 53 and TLS in AWS Certificate Manager (ACM)
- Send all logs and metrics to CloudWatch
- Configure alerts in CloudWatch for CPU, memory, and disk space usage
- Manage SSH access with IAM groups using
ssh-grunt
- Manage deployment permissions for the server using IAM roles
- OS hardening, including
fail2ban
,ntp
,auto-update
,ip-lockdown
, and more
Learn
note
This repo is a part of the Gruntwork Service Catalog, a collection of reusable, battle-tested, production ready infrastructure code. If you’ve never used the Service Catalog before, make sure to read How to use the Gruntwork Service Catalog!
CI/ CD Core Concepts: An overview of the core concepts you need to understand what a typical CI/CD pipeline entails for application and infrastructure code, including a sample workflow, infrastructure to support CI/CD, an threat models to consider to protect your infrastructure.
Jenkins Documentation: The official documentation for Jenkins.
Deploy
Non-production deployment (quick start for learning)
If you just want to try this repo out for experimenting and learning, check out the following resources:
- examples/for-learning-and-testing folder: The
examples/for-learning-and-testing
folder contains standalone sample code optimized for learning, experimenting, and testing (but not direct production usage).
Production deployment
If you want to deploy this repo in production, check out the following resources:
examples/for-production folder: The
examples/for-production
folder contains sample code optimized for direct usage in production. This is code from the Gruntwork Reference Architecture, and it shows you how we build an end-to-end, integrated tech stack on top of the Gruntwork Service Catalog.How to configure a production-grade CI/CD workflow for application and infrastructure code: step-by-step guide on how to configure CI / CD for your apps and infrastructure.
Reference
- Inputs
- Outputs
Required
The domain name used for an SSL certificate issued by the Amazon Certificate Manager (ACM).
alb_subnet_ids
list(string)The IDs of the subnets in which to deploy the ALB that runs in front of Jenkins. Must be subnets in vpc_id
.
ami
stringThe ID of the AMI to run on the Jenkins server. This should be the AMI build from the Packer template jenkins-ubuntu.json. One of ami
or ami_filters
is required. Set to null if looking up the ami with filters.
ami_filters
object(…)Properties on the AMI that can be used to lookup a prebuilt AMI for use with Jenkins. You can build the AMI using the Packer template jenkins-ubuntu.json. Only used if ami
is null. One of ami
or ami_filters
is required. Set to null if passing the ami ID directly.
object({
# List of owners to limit the search. Set to null if you do not wish to limit the search by AMI owners.
owners = list(string)
# Name/Value pairs to filter the AMI off of. There are several valid keys, for a full reference, check out the
# documentation for describe-images in the AWS CLI reference
# (https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-images.html).
filters = list(object({
name = string
values = list(string)
}))
})
domain_name
stringThe domain name for the DNS A record to add for Jenkins (e.g. jenkins.foo.com). Must be in the domain managed by hosted_zone_id
.
hosted_zone_id
stringThe ID of the Route 53 Hosted Zone in which to create a DNS A record for Jenkins.
instance_type
stringThe instance type to use for the Jenkins server (e.g. t2.medium)
jenkins_subnet_id
stringThe ID of the subnet in which to deploy Jenkins. Must be a subnet in vpc_id
.
memory
stringThe amount of memory to give Jenkins (e.g., 1g or 512m). Used for the -Xms and -Xmx settings.
vpc_id
stringThe ID of the VPC in which to deploy Jenkins
Optional
alarms_sns_topic_arn
list(string)The ARNs of SNS topics where CloudWatch alarms (e.g., for CPU, memory, and disk space usage) should send notifications. Also used for the alarms if the Jenkins backup job fails.
[]
allow_incoming_http_from_cidr_blocks
list(string)The IP address ranges in CIDR format from which to allow incoming HTTP requests to Jenkins.
[]
allow_incoming_http_from_security_group_ids
list(string)The IDs of security groups from which to allow incoming HTTP requests to Jenkins.
[]
allow_ssh_from_cidr_blocks
list(string)The IP address ranges in CIDR format from which to allow incoming SSH requests to Jenkins.
[]
allow_ssh_from_security_group_ids
list(string)The IDs of security groups from which to allow incoming SSH requests to Jenkins.
[]
backup_job_alarm_period
numberHow often, in seconds, the backup job is expected to run. This is the same as backup_job_schedule_expression
, but unfortunately, Terraform offers no way to convert rate expressions to seconds. We add a CloudWatch alarm that triggers if the value of backup_job_metric_name
and backup_job_metric_namespace
isn't updated within this time period, as that indicates the backup failed to run.
86400
backup_job_metric_name
stringThe name for the CloudWatch Metric the AWS lambda backup job will increment every time the job completes successfully.
"jenkins-backup-job"
The namespace for the CloudWatch Metric the AWS lambda backup job will increment every time the job completes successfully.
"Custom/Jenkins"
A cron or rate expression that specifies how often to take a snapshot of the Jenkins server for backup purposes. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html for syntax details.
"rate(1 day)"
backup_using_dlm
boolSet to true to backup the Jenkins Server using AWS Data Lifecycle Management Policies.
true
Set to true to backup the Jenkins Server using a Scheduled Lambda Function.
false
build_permission_actions
list(string)The list of IAM actions this Jenkins server should be allowed to do: e.g., ec2:, s3:, etc. This should be the list of IAM permissions Jenkins needs in this AWS account to run builds. These permissions will be added to the server's IAM role for all resources ('*').
[]
cloud_init_parts
map(object(…))Cloud init scripts to run on the Jenkins server when it is booting. See the part blocks in https://www.terraform.io/docs/providers/template/d/cloudinit_config.html for syntax.
map(object({
filename = string
content_type = string
content = string
}))
{}
The ID (ARN, alias ARN, AWS ID) of a customer managed KMS Key to use for encrypting log data.
null
The number of days to retain log events in the log group. Refer to https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group#retention_in_days for all the valid values. When null, the log events are retained forever.
null
cloudwatch_log_group_tags
map(string)Tags to apply on the CloudWatch Log Group, encoded as a map where the keys are tag keys and values are tag values.
null
Set to true to create a public DNS A record in Route53 for Jenkins.
true
custom_tags
map(string)A list of custom tags to apply to Jenkins and all other resources.
{}
default_user
stringThe default OS user for the Jenkins AMI. For AWS Ubuntu AMIs, which is what the Packer template in jenkins-ubunutu.json uses, the default OS user is 'ubuntu'.
"ubuntu"
How often this lifecycle policy should be evaluated, in hours.
24
The name of the data lifecyle management schedule
"daily-last-two-weeks"
How many snapshots to keep. Must be an integer between 1 and 1000.
15
dlm_backup_job_schedule_times
list(string)A list of times in 24 hour clock format that sets when the lifecyle policy should be evaluated. Max of 1.
[ "03:00"
]
ebs_kms_key_arn
stringThe ARN of the KMS key used for encrypting the Jenkins EBS volume. The module will grant Jenkins permission to use this key.
null
Whether or not the provide EBS KMS key ARN is a key alias. If providing the key ID, leave this set to false.
false
Set to true to enable several basic CloudWatch alarms around CPU usage, memory usage, and disk space usage. If set to true, make sure to specify SNS topics to send notifications to using alarms_sns_topic_arn
.
true
Set to true to add AIM permissions to send logs to CloudWatch. This is useful in combination with https://github.com/gruntwork-io/terraform-aws-monitoring/tree/master/modules/logs/cloudwatch-log-aggregation-scripts to do log aggregation in CloudWatch.
true
Set to true to add IAM permissions to send custom metrics to CloudWatch. This is useful in combination with https://github.com/gruntwork-io/terraform-aws-monitoring/tree/master/modules/agents/cloudwatch-agent to get memory and disk metrics in CloudWatch for your Jenkins server.
true
Enable ip-lockdown to block access to the instance metadata. Defaults to true.
true
enable_ssh_grunt
boolSet to true to add IAM permissions for ssh-grunt (https://github.com/gruntwork-io/terraform-aws-security/tree/master/modules/ssh-grunt), which will allow you to manage SSH access via IAM groups.
true
external_account_auto_deploy_iam_role_arns
list(string)A list of IAM role ARNs in other AWS accounts that Jenkins will be able to assume to do automated deployment in those accounts.
[]
If you are using ssh-grunt and your IAM users / groups are defined in a separate AWS account, you can use this variable to specify the ARN of an IAM role that ssh-grunt can assume to retrieve IAM group and public SSH key info from that account. To omit this variable, set it to an empty string (do NOT use null, or Terraform will complain).
""
The period, in seconds, over which to measure the CPU utilization percentage for the ASG.
60
Trigger an alarm if the ASG has an average cluster CPU utilization percentage above this threshold.
90
Sets how this alarm should handle entering the INSUFFICIENT_DATA state. Based on https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-missing-data. Must be one of: 'missing', 'ignore', 'breaching' or 'notBreaching'.
"missing"
The period, in seconds, over which to measure the root disk utilization percentage for the ASG.
60
Trigger an alarm if the ASG has an average cluster root disk utilization percentage above this threshold.
90
Sets how this alarm should handle entering the INSUFFICIENT_DATA state. Based on https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-missing-data. Must be one of: 'missing', 'ignore', 'breaching' or 'notBreaching'.
"missing"
The period, in seconds, over which to measure the Memory utilization percentage for the ASG.
60
Trigger an alarm if the ASG has an average cluster Memory utilization percentage above this threshold.
90
Sets how this alarm should handle entering the INSUFFICIENT_DATA state. Based on https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-missing-data. Must be one of: 'missing', 'ignore', 'breaching' or 'notBreaching'.
"missing"
is_internal_alb
boolSet to true to make the Jenkins ALB an internal ALB that cannot be accessed from the public Internet. We strongly recommend setting this to true to keep Jenkins more secure.
true
jenkins_device_name
stringThe OS device name where the Jenkins EBS volume should be attached
"xvdh"
jenkins_mount_point
stringThe OS path where the Jenkins EBS volume should be mounted
"/jenkins"
jenkins_user
stringThe OS user that should be used to run Jenkins
"jenkins"
Sets how the backup job alarm should handle entering the INSUFFICIENT_DATA state. Based on https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-missing-data. Must be one of: 'missing', 'ignore', 'breaching' or 'notBreaching'.
"missing"
Set to true to encrypt the Jenkins EBS volume.
true
jenkins_volume_size
numberThe amount of disk space, in GB, to allocate for the EBS volume used by the Jenkins server.
200
jenkins_volume_type
stringThe type of volume to use for the EBS volume used by the Jenkins server. Must be one of: standard, gp2, io1, sc1, or st1.
"gp2"
keypair_name
stringThe name of a Key Pair that can be used to SSH to the Jenkins server. Leave blank if you don't want to enable Key Pair auth.
null
name
stringEnter the name of the Jenkins server
"jenkins"
The type of volume to use for the root disk for Jenkins. Must be one of: standard, gp2, io1, sc1, or st1.
"gp2"
root_volume_size
numberThe amount of disk space, in GB, to allocate for the root volume of this server. Note that all of Jenkins' data is stored on a separate EBS Volume (see jenkins_volume_size
), so this root volume is primarily used for the OS, temp folders, apps, etc.
100
When true, precreate the CloudWatch Log Group to use for log aggregation from the EC2 instances. This is useful if you wish to customize the CloudWatch Log Group with various settings such as retention periods and KMS encryption. When false, the CloudWatch agent will automatically create a basic log group to use.
true
If set to true, skip the health check, and start a rolling deployment of Jenkins without waiting for it to initially be in a healthy state. This is primarily useful if the server group is in a broken state and you want to force a deployment anyway.
false
ssh_grunt_iam_group
stringIf you are using ssh-grunt, this is the name of the IAM group from which users will be allowed to SSH to this Jenkins server. This value is only used if enable_ssh_grunt=true.
"ssh-grunt-users"
ssh_grunt_iam_group_sudo
stringIf you are using ssh-grunt, this is the name of the IAM group from which users will be allowed to SSH to this Jenkins server with sudo permissions. This value is only used if enable_ssh_grunt=true.
"ssh-grunt-sudo-users"
tenancy
stringThe tenancy of this server. Must be one of: default, dedicated, or host.
"default"
When true, all IAM policies will be managed as dedicated policies rather than inline policies attached to the IAM roles. Dedicated managed policies are friendlier to automated policy checkers, which may scan a single resource for findings. As such, it is important to avoid inline policies when targeting compliance with various security standards.
true
The ARN of the ALB deployed in front of Jenkins
The DNS name of the ALB deployed in front of Jenkins
The hosted zone ID of the ALB deployed in front of Jenkins
The ARNs of just the HTTP ALB listeners of the ALB deployed in front of Jenkins
The ARNs of just the HTTPS ALB listeners that usse ACM certs of the ALB deployed in front of Jenkins
The ARNs of just the HTTPS ALB listeners that use non-ACM certs of the ALB deployed in front of Jenkins
The ARNs of the ALB listeners of the ALB deployed in front of Jenkins
The name of the ALB deployed in front of Jenkins
The ID of the security group attached to the ALB deployed in front of Jenkins
The name of the Auto Scaling Group in which Jenkins is running
The public domain name configured for Jenkins
The ID of the EBS Volume that will store the JENKINS_HOME directory
The ARN of the IAM role attached to the Jenkins EC2 Instance
The ID of the IAM role attached to the Jenkins EC2 Instance
The ID of the Security Group attached to the Jenkins EC2 Instance