Skip to content

Commit

Permalink
feat: bootstrap Jenkins agent with CFT dependencies (terraform-google…
Browse files Browse the repository at this point in the history
  • Loading branch information
caleonardo authored Jul 18, 2020
1 parent e7ef9c2 commit 124629d
Show file tree
Hide file tree
Showing 7 changed files with 465 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ The objective of this module is to deploy a Google Cloud Platform project `prj-c
- TODO: use a fixed IP or no public IP at all
- Custom Service account to run the Jenkins Agent's GCE Instance

## Usage
Please note this module does not include an option to create a Jenkins Master. To deploy a Jenkins Master, you should follow one of the available user guides in https://cloud.google.com/jenkins.

If you don't have a Jenkins implementation and don't want one, then we recommend you to use the Cloud Build module instead of this Jenkins module.

1. Add the SSH public keys of your Jenkins Agent in the file `./jenkins-agent-ssh-pub-keys/metadata-ssh-pub-keys`
## Usage

1. While developing only - Run `$ gcloud auth application-default login` before running `$ terraform plan` to avoid the errors below:
```
Expand Down Expand Up @@ -46,54 +48,55 @@ Error: google: could not find default credentials. See https://developers.google

## Features

1. Create a new GCP project using `project_prefix`
1. Enable APIs in the project using `activate_apis`
1. Create a GCE Instance to run the Jenkins Agent with SSH access using the supplied public key
1. TODO:
1. Create a GCS bucket for Jenkins Artifacts using `project_prefix`
1. Create KMS Keyring and key for encryption
1. Grant access to decrypt to `terraform_sa_email` and to `jenkins_sa_email` (Jenkins GCE Instance custom service account)
1. Grant access to encrypt to `group_org_admins`
1. Optionally give `jenkins_sa_email` service account permissions to impersonate terraform service account using `sa_enable_impersonation` and supplied value for `terraform_sa_name`



## Resources created

- TODO
- KMS Keyring and key for secrets, including IAM for Cloudbuild, Org Admins and Terraform service account
- (optional) Cloudbuild impersonation permissions for a service account
- (optional) Cloud Source Repos, with triggers for terraform plan (all other branches) & terraform apply (master)

1. Creates a new GCP project using `project_prefix`
1. Enables APIs in the project using `activate_apis`
1. Creates a GCE Instance to run the Jenkins Agent with SSH access using the supplied public key
1. Creates a Service Account (`jenkins_agent_sa_email`) to run the Jenkins Agent GCE instance
1. Creates a GCS bucket for Jenkins Artifacts using `project_prefix`
1. Allows `jenkins_agent_sa_email` service account permissions to impersonate terraform service account (which exists in the `seed` project) using `sa_enable_impersonation` and supplied value for `terraform_sa_name`

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|:----:|:-----:|:-----:|
| activate\_apis | List of APIs to enable in the Cloudbuild project. | list(string) | `<list>` | no |
| activate\_apis | List of APIs to enable in the CICD project. | list(string) | `<list>` | no |
| billing\_account | The ID of the billing account to associate projects with. | string | n/a | yes |
| default\_region | Default region to create resources where applicable. | string | `"us-central1"` | no |
| folder\_id | The ID of a folder to host this project | string | `""` | no |
| group\_org\_admins | Google Group for GCP Organization Administrators | string | n/a | yes |
| jenkins\_agent\_gce\_machine\_type | Jenkins Agent GCE Instance type. | string | `"n1-standard-1"` | no |
| jenkins\_agent\_gce\_name | Jenkins Agent GCE Instance name. | string | `"jenkins-agent-01"` | no |
| jenkins\_agent\_gce\_ssh\_pub\_key | SSH public key needed by the Jenkins Agent GCE Instance. The Jenkins Master holds the SSH private key. | string | `"ssh-rsa [KEY_VALUE] [USERNAME]"` | no |
| jenkins\_agent\_gce\_private\_ip\_address | The private IP Address of the Jenkins Agent. This IP Address must be in the CIDR range of `jenkins_agent_gce_subnetwork_cidr_range` and be reachable through the VPN that exists between on-prem (Jenkins Master) and GCP (CICD Project, where the Jenkins Agent is located). | string | n/a | yes |
| jenkins\_agent\_gce\_ssh\_pub\_key | SSH public key needed by the Jenkins Agent GCE Instance. The Jenkins Master holds the SSH private key. The correct format is `'ssh-rsa [KEY_VALUE] [USERNAME]'` | string | `""` | no |
| jenkins\_agent\_gce\_ssh\_user | Jenkins Agent GCE Instance SSH username. | string | `"jenkins"` | no |
| jenkins\_agent\_gce\_subnetwork\_cidr\_range | The subnetwork to which the Jenkins Agent will be connected to (in CIDR range 0.0.0.0/0) | string | n/a | yes |
| jenkins\_agent\_sa\_email | Email for Jenkins Agent service account. | string | `"jenkins-agent-gce"` | no |
| jenkins\_master\_ip\_addresses | A list of IP Addresses and masks of the Jenkins Master in the form ['0.0.0.0/0']. Needed to create a FW rule that allows communication with the Jenkins Agent GCE Instance. | list(string) | n/a | yes |
| jenkins\_sa\_email | Email for Jenkins Agent service account. | string | `"jenkins-agent-gce-sa"` | no |
| nat\_bgp\_asn | BGP ASN for NAT cloud route. This is needed to allow the Jenkins Agent to download packages and updates from the internet without having an external IP address. | number | n/a | yes |
| org\_id | GCP Organization ID | string | n/a | yes |
| project\_labels | Labels to apply to the project. | map(string) | `<map>` | no |
| project\_prefix | Name prefix to use for projects created. | string | `"prj"` | no |
| sa\_enable\_impersonation | Allow org_admins group to impersonate service account & enable APIs required. | bool | `"false"` | no |
| service\_account\_prefix | Name prefix to use for service accounts. | string | `"sa"` | no |
| skip\_gcloud\_download | Whether to skip downloading gcloud (assumes gcloud is already available outside the module) | bool | `"true"` | no |
| storage\_bucket\_labels | Labels to apply to the storage bucket. | map(string) | `<map>` | no |
| storage\_bucket\_prefix | Name prefix to use for storage buckets. | string | `"bkt"` | no |
| terraform\_sa\_email | Email for terraform service account. It must be supplied by the seed project | string | n/a | yes |
| terraform\_sa\_name | Fully-qualified name of the terraform service account. It must be supplied by the seed project | string | n/a | yes |
| terraform\_state\_bucket | Default state bucket, used in Cloud Build substitutions. It must be supplied by the seed project | string | n/a | yes |
| terraform\_version | Default terraform version. | string | `"0.12.24"` | no |
| terraform\_version\_sha256sum | sha256sum for default terraform version. | string | `"602d2529aafdaa0f605c06adb7c72cfb585d8aa19b3f4d8d189b42589e27bf11"` | no |

## Outputs

| Name | Description |
|------|-------------|
| cicd\_project\_id | Project where the cicd pipeline (Jenkins Agents and terraform builder container image) reside. |
| gcs\_bucket\_jenkins\_artifacts | Bucket used to store Jenkins artifacts in Jenkins project. |
| jenkins\_agent\_gce\_instance\_id | Jenkins Agent GCE Instance id. |
| jenkins\_sa\_email | Email for privileged custom service account for Jenkins Agent GCE instance. |
| jenkins\_sa\_name | Fully qualified name for privileged custom service account for Jenkins Agent GCE instance. |
| jenkins\_agent\_sa\_email | Email for privileged custom service account for Jenkins Agent GCE instance. |
| jenkins\_agent\_sa\_name | Fully qualified name for privileged custom service account for Jenkins Agent GCE instance. |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

Expand All @@ -106,6 +109,17 @@ Error: google: could not find default credentials. See https://developers.google
- [terraform-provider-google] plugin 2.1.x
- [terraform-provider-google-beta] plugin 2.1.x

### Infrastructure

- **Jenkins Master:** You need a Jenkins Master. Please note this module does not include an option to create a Jenkins Master. To deploy a Jenkins Master, you should follow one of the available user guides about [Jenkins in GCP](https://cloud.google.com/jenkins). If you don't have a Jenkins implementation and don't want one, then we recommend you to use the Cloud Build module instead of this Jenkins module.

- **VPN Connectivity with on-prem:** Once you run this module and your Jenkins Agent is created in the CICD project in GCP, please add VPN connectivity manually by following our user guide about [how to deploy a VPN tunnel in GCP](https://cloud.google.com/network-connectivity/docs/vpn/how-to). This VPN configuration is necessary to allow communication between the Jenkins Master (on prem or in a cloud environment) with the Jenkins Agent in the CICD project. The reason why you add this connection manually is because you need to keep the VPN secret away from any configuration file, such as the Terraform state.

- **Binaries and packages:** The Jenkins Agent needs to fetch several binaries needed to execute pipelines. These include `java`, `terraform`, `terraform-validator` and the terraform modules used by the scripts provided here and the terraform modules you use in your own scripts. You have several options to have these binaries and libraries available:
- having Internet access (ideally through Cloud NAT).
- having a local repository on your premises that the Agent can reach out to.
- preparing a golden image for `jenkins_agent_gce_instance.boot_disk.initialize_params.image` (although, you might still need network access to download dependencies while running a pipeline).

### Permissions

- `roles/billing.user` on supplied billing account
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#!/bin/sh

echo "**** Startup Step 1/6: Update apt-get repositories. ****"
apt-get update

echo "**** Startup Step 2/6: Install Java. Needed to accept jobs from Jenkins Master. ****"
apt-get install -y default-jdk

echo "**** Startup Step 3/6: Install tools needed to run pipeline commands. ****"
apt-get install -y git jq unzip google-cloud-sdk google-cloud-sdk

echo "**** Startup Step 4/6: Create a directory to locate Terraform binaries. ****"
# shellcheck disable=SC2154
mkdir -p "${tpl_TERRAFORM_DIR}" && cd "${tpl_TERRAFORM_DIR}" || exit

echo "**** Startup Step 5/6: Download, verify and unzip Terraform binaries. ****"
# shellcheck disable=SC2154
wget "https://releases.hashicorp.com/terraform/${tpl_TERRAFORM_VERSION}/terraform_${tpl_TERRAFORM_VERSION}_linux_amd64.zip" && \
echo "${tpl_TERRAFORM_VERSION_SHA256SUM} terraform_${tpl_TERRAFORM_VERSION}_linux_amd64.zip" > terraform_SHA256SUMS && \
sha256sum -c terraform_SHA256SUMS --status && \
unzip "terraform_${tpl_TERRAFORM_VERSION}_linux_amd64.zip" -d "${tpl_TERRAFORM_DIR}" && \
chmod 755 terraform && \
rm -f "${tpl_TERRAFORM_DIR}terraform_${tpl_TERRAFORM_VERSION}_linux_amd64.zip" && \
apt-get remove --purge -y curl unzip && \
apt-get --purge -y autoremove && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

echo "**** Startup Step 6/6: Download and install the Terraform validator ****"
gsutil cp gs://terraform-validator/releases/2019-04-04/terraform-validator-linux-amd64 .
chmod 755 "${tpl_TERRAFORM_DIR}terraform-validator-linux-amd64"
mv "${tpl_TERRAFORM_DIR}terraform-validator-linux-amd64" "${tpl_TERRAFORM_DIR}terraform-validator"
Loading

0 comments on commit 124629d

Please sign in to comment.