The purpose of this step is to bootstrap a GCP organization, creating all the required resources & permissions to start using the Cloud Foundation Toolkit (CFT). This step also guides you on how to configure a CICD project to host a Jenkins Agent, which connects to your existing Jenkins Controller infrastructure & your own Git repos (which might live on-prem). The Jenkins Agent will run CICD pipelines for foundations code in subsequent stages.
Another CICD option is to use Cloud Build & Cloud Source Repos. If you don't have a Jenkins implementation and don't want one, then we recommend you to use the Cloud Build module instead.
The objective of the instructions below is to configure the infrastructure that allows you to run CICD deployments for the next stages (1-org, 2-environments, 3-networks, 4-projects
) using Jenkins. The infrastructure consists in two Google Cloud Platform projects (prj-b-seed
and prj-b-cicd
) and VPN configuration to connect to your on-prem environment.
It is a best practice to have two separate projects here (prj-b-seed
and prj-b-cicd
) for separation of concerns. On one hand, prj-b-seed
stores terraform state and has the Service Account able to create / modify infrastructure. On the other hand, the deployment of that infrastructure is coordinated by Jenkins, which is implemented in prj-b-cicd
and connected to your Controller on-prem.
After following the instructions below, you will have:
-
The
prj-b-seed
project, which contains:- Terraform state bucket
- Custom Service Account used by Terraform to create new resources in GCP
-
The
prj-b-cicd
project, which contains:- GCE Instance for the Jenkins Agent, connected to your current Jenkins Controller using SSH.
- VPC to connect the Jenkins GCE Instance to
- FW rules to allow communication over port 22
- VPN connection with on-prem (or where ever your Jenkins Controller is located)
- Custom service account
[email protected]
for the GCE instance.- This service account is granted the access to generate tokens on the Terraform custom service account in the
prj-b-seed
project
- This service account is granted the access to generate tokens on the Terraform custom service account in the
-
Note: these instructions do not indicate how to create a Jenkins Controller. To deploy a Jenkins Controller, you should follow Jenkins Architecture recommendations.
If you don't have a Jenkins implementation and don't want one, then we recommend you to use the Cloud Build module instead.
Please see the requirements of Software, Infrastructure and Permissions before following the instructions below.
Note: If you are using MacOS, replace cp -RT
with cp -R
in the relevant
commands. The -T
flag is needed for Linux, but causes problems for MacOS.
You arrived to these instructions because you are using the jenkins_bootstrap
to run the 0-bootstrap step instead of cloudbuild_bootstrap
. Please follow the indications below:
- Make sure you cover all the requirements of Software, Infrastructure and Permissions before following the instructions below.
- Required information:
- Access to the Jenkins Controller host to run
ssh-keygen
command - Access to the Jenkins Controller Web UI
- SSH Agent Jenkins plugin installed in your Jenkins Controller
- Private IP address for the Jenkins Agent: usually assigned by your network administrator. You will use this IP for the GCE instance that will be created in the
prj-b-cicd
GCP Project in step II. Create the SEED and CICD projects using Terraform. - Access to create five Git repositories, one for each directory in this monorepo (
0-bootstrap, 1-org, 2-environments, 3-networks, 4-projects
). These are usually private repositories that might be on-prem.
- Access to the Jenkins Controller host to run
-
Generate a SSH key pair. In the Jenkins Controller host, use the
ssh-keygen
command to generate a SSH key pair.-
You will need this key pair to enable authentication between the Controller and Agent. Although the key pair can be generated in any linux machine, it is recommended not to copy the secret private key from one host to another, so you probably want to do this in the Jenkins Controller host command line.
-
Note the
ssh-keygen
command uses the-N
option to protect the private key with a password. In this example, we are using-N "my-password"
. This is important because you will need both, the private key and the password when configuring the SSH Agent in you Jenkins Controller Web UI.SSH_LOCAL_CONFIG_DIR="$HOME/.ssh" JENKINS_USER="jenkins" JENKINS_AGENT_NAME="AgentGCE1" SSH_KEY_FILE_PATH="$SSH_LOCAL_CONFIG_DIR/$JENKINS_USER-${JENKINS_AGENT_NAME}_rsa" mkdir "$SSH_LOCAL_CONFIG_DIR" ssh-keygen -t rsa -m PEM -N "my-password" -C $JENKINS_USER -f $SSH_KEY_FILE_PATH cat $SSH_KEY_FILE_PATH
-
You will see an output similar to this:
-----BEGIN RSA PRIVATE KEY----- copy your private key from BEGIN to END And configure a new Jenkins Agent in the Web UI -----END RSA PRIVATE KEY-----
-
-
Configure a new SSH Jenkins Agent in the Jenkins Controller’s Web UI. You need the following information:
- SSH Agent Jenkins plugin installed in your Controller
- SSH private key you just generated in the previous step
- Passphrase that protects the private key (the one you used in the
-N
option) - Jenkins Agent’s private IP address (usually assigned by your Network Administrator. In the provided examples this IP is "172.16.1.6"). This private IP will be reachable through the VPN connection that you will create later.
-
Create five individual Git repositories in your Git server (This might be a task delegated to your infrastructure team)
- Note that although this infrastructure code is distributed to you as a monorepo, you will store the code in five different repositories, one for each directory:
./0-bootstrap ./1-org ./2-environments ./3-networks ./4-projects
- For simplicity, let's name your five repositories as follows:
YOUR_NEW_REPO-0-bootstrap YOUR_NEW_REPO-1-org YOUR_NEW_REPO-2-environments YOUR_NEW_REPO-3-networks YOUR_NEW_REPO-4-projects
- Note: Towards the end of these instructions, you will configure your Jenkins Controller with new automatic pipelines only for the following repositories:
YOUR_NEW_REPO-1-org YOUR_NEW_REPO-2-environments YOUR_NEW_REPO-3-networks YOUR_NEW_REPO-4-projects
- Note: there is no automatic pipeline needed for
YOUR_NEW_REPO-0-bootstrap
- Note: there is no automatic pipeline needed for
- In this 0-bootstrap section we only work with your new repository that is a copy of the directory
./0-bootstrap
(YOUR_NEW_REPO-0-bootstrap
)
- Note that although this infrastructure code is distributed to you as a monorepo, you will store the code in five different repositories, one for each directory:
-
Clone this mono-repository with
git clone https://github.com/terraform-google-modules/terraform-example-foundation
-
Clone the repository you created to host the
0-bootstrap
directory withgit clone <YOUR_NEW_REPO-0-bootstrap>
-
Navigate into the freshly cloned repo
cd <YOUR_NEW_REPO-0-bootstrap>
and change to a new branchgit checkout -b my-0-bootstrap
-
Copy contents of foundation to new repo
cp -RT ../terraform-example-foundation/0-bootstrap/ .
(modify accordingly based on your current directory). -
Activate the Jenkins module and disable the Cloud Build module. This implies manually editing the following files:
- Comment-out the
cloudbuild_bootstrap
module in./main.tf
- Comment-out the
cloudbuild_bootstrap
outputs in./outputs.tf
- Un-comment the
jenkins_bootstrap
module in./main.tf
- Un-comment the
jenkins_bootstrap
variables in./variables.tf
- Un-comment the
jenkins_bootstrap
outputs in./outputs.tf
- Comment-out the
-
Rename
terraform.example.tfvars
toterraform.tfvars
and update the file with values from your environment.- One of the value to supply (variable
jenkins_agent_gce_ssh_pub_key
) is the public SSH key you generated in the first step.- Note: this is not the secret private key. The public SSH key can be in your repository code.
- Show the public key using
cat "${SSH_KEY_FILE_PATH}.pub"
, you will copy / paste it in theterraform.tfvars
file (variablejenkins_agent_gce_ssh_pub_key
). - Provide the rest of the values needed in
terraform.tfvars
- One of the value to supply (variable
-
Commit changes with
git add .
andgit commit -m 'Your message - Bootstrap configuration using jenkins_module'
-
Push my-0-bootstrap branch to your repository YOUR_NEW_REPO-0-bootstrap with
git push --set-upstream origin my-0-bootstrap
- Required information:
- Terraform version 0.13.7 - See Requirements section for more details.
- The
terraform.tfvars
file with all the necessary values.
-
Get the appropriate credentials: run the following command with an account that has the necessary permissions.
gcloud auth application-default login
- Open the link in your browser and accept.
-
Run terraform commands.
- After the credentials are configured, we will create the
prj-b-seed
project (which contains the GCS state bucket and Terraform custom service account) and theprj-b-cicd
project (which contains the Jenkins Agent, its custom service account and where we will add VPN configuration) - WARNING: Make sure you have commented-out the
cloudbuild_bootstrap
module and enabled thejenkins_bootstrap
module in the./main.tf
file - Use Terraform 0.13.7 to run the terraform script with the commands below
terraform init terraform plan terraform apply
- The Terraform script will take about 10 to 15 minutes. Once it finishes, note that communication between on-prem and the
prj-b-cicd
project won’t happen yet - you will configure the VPN network connectivity in step III. Create VPN connection.
- After the credentials are configured, we will create the
-
Move Terraform State to the GCS bucket created in the seed project
- Run
terraform output gcs_bucket_tfstate
to get the tfstate bucket name - Rename
backend.tf.example
tobackend.tf
- Edit file
backend.tf
and replaceUPDATE_ME
with the tfstate bucket name
- Run
-
Re-run
terraform init
and agree to copy state to gcs when prompted- (Optional) Run
terraform apply
to verify state is configured correctly. You can confirm the terraform state is now in that bucket by visiting the bucket url in your seed project.
- (Optional) Run
-
Commit changes with
git add backend.tf
andgit commit -m 'Your message - Terraform Backend configuration using GCS'
-
Push my-0-bootstrap branch to your repository YOUR_NEW_REPO-0-bootstrap with
git push
Here you will configure a VPN Network tunnel to enable connectivity between the prj-b-cicd
project and your on-prem environment. Learn more about a VPN tunnel in GCP.
- Required information:
- On-prem VPN public IP Address
- Jenkins Controller’s network CIDR (the example code uses "10.1.0.0/24")
- Jenkins Agent network CIDR (the example code uses "172.16.1.0/24")
- VPN PSK (pre-shared secret key)
- Check in the
prj-b-cicd
project for the VPN gateway static IP addresses which have been reserved. These addresses are required by the Network Administrator for the configuration of the on-prem side of the VPN tunnels to GCP.
- Assuming your network administrator already configured the on-prem end of the VPN, the CICD end of the VPN might show the message
First Handshake
for around 5 minutes. - When the VPN is ready, the status will show
Tunnel is up and running
. At this point, your Jenkins Controller (on-prem) and Jenkins Agent (inprj-b-cicd
project) must have network connectivity through the VPN.
- Test a pipeline using the Jenkins Controller Web UI:
-
Note: this section is considered out of the scope of this document. Since there are multiple options on how to configure the Git repositories and Multibranch Pipeline in your Jenkins Controller, here we can only provide some guidance that you should keep in mind while completing this step. Visit the Jenkins website for more information, there are plenty of Jenkins Plugins that could help with the task.
- You need to configure a "Multibranch Pipeline". Note that the
Jenkinsfile
andtf-wrapper.sh
files use the$BRANCH_NAME
environment variable. the$BRANCH_NAME
variable is only available in Jenkins' Multibranch Pipelines.
- You need to configure a "Multibranch Pipeline". Note that the
-
Jenkinsfile: A Jenkinsfile has been included which closely aligns with the Cloud Build pipeline. Additionally, the stage
TF wait for approval
which lets you confirm via Jenkins UI before proceeding withterraform apply
has been disabled by default. It can be enabled by un-commenting that stage in the file.
-
Create Multibranch pipelines for your new repos (
YOUR_NEW_REPO-1-org, YOUR_NEW_REPO-2-environments, YOUR_NEW_REPO-3-networks, YOUR_NEW_REPO-4-projects
).- DO NOT configure an automatic pipeline for your
YOUR_NEW_REPO-0-bootstrap
repository
- DO NOT configure an automatic pipeline for your
-
In your Jenkins Controller Web UI, create Multibranch Pipelines only for the following repositories:
YOUR_NEW_REPO-1-org YOUR_NEW_REPO-2-environments YOUR_NEW_REPO-3-networks YOUR_NEW_REPO-4-projects
-
Assuming your new Git repositories are private, you may need to configure new credentials In your Jenkins Controller web UI, so it can connect to the repositories.
-
You will also want to configure automatic triggers in each one of the Jenkins Multibranch Pipelines, unless you want to run the pipelines manually from the Jenkins Web UI after each commit to your repositories.
-
You can now move to the instructions in the step 1-org.
Refer to the contribution guidelines for information on contributing to this module.