Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/jenkins #43

Open
wants to merge 21 commits into
base: GDC-phase-kickstarter-1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions examples/guardrails/folder-factory/Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
pipeline {
agent any
environment {
BUCKET_PATH = credentials('backend-path')
REPO_FULL_NAME = credentials('bucket-repo')
PROJECT_NAME = credentials('project-name')
GCP_PROJECT_NUMBER = credentials('project-id')
workload_identity_pool_id = credentials('wif_pool_id')
workload_identity_pool_provider_id = credentials('wif_pool_provider_id')
SERVICE_ACCOUNT_NAME = credentials('sa-name')
policy_file_path = credentials('policy_file_path')
}
options {
skipDefaultCheckout(true)
}
stages {
stage('clean workspace') {
steps {
cleanWs()
}
}
stage('WIF') {
steps {
withCredentials([file(variable: 'ID_TOKEN_FILE', credentialsId: 'gcp')]) {
writeFile file: "$WORKSPACE_TMP/creds.json", text: """
{
"type": "external_account",
"audience": "//iam.googleapis.com/projects/${GCP_PROJECT_NUMBER}/locations/global/workloadIdentityPools/${workload_identity_pool_id}/providers/${workload_identity_pool_provider_id}",
"subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
"token_url": "https://sts.googleapis.com/v1/token",
"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SERVICE_ACCOUNT_NAME}@${PROJECT_NAME}.iam.gserviceaccount.com:generateAccessToken",
"credential_source": {
"file": "$ID_TOKEN_FILE",
"format": {
"type": "text"
}
}
}
"""
sh '''
gcloud auth login --brief --cred-file=$WORKSPACE_TMP/creds.json
'''
}
}
}
stage('checkout') {
steps {
checkout scm
}
}
stage('Terraform Plan') {
steps {

sh '''
cd guardrails/folder-factory
terraform init -backend-config="bucket=${BUCKET_PATH}" -backend-config="prefix=${REPO_FULL_NAME}"
terraform plan -input=false -out ffjenkins.tfplan
'''
}
}
stage('Terraform Validate') {
steps {
sh '''
cd guardrails/folder-factory
terraform show -json "ffjenkins.tfplan" > "ffjenkins.json"
gcloud source repos clone gcp-policies "${policy_file_path}" --project="${GCP_PROJECT_NUMBER}"
gcloud beta terraform vet "ffjenkins.json" --policy-library="${policy_file_path}" --project="${GCP_PROJECT_NUMBER}"
'''
}
}
stage('Terraform Apply') {
steps {
sh '''
cd guardrails/folder-factory
terraform apply -auto-approve
'''
}
}
}
}

41 changes: 41 additions & 0 deletions examples/guardrails/folder-factory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,44 @@ iam:
```

Every folder is defined with its own yaml file located in the following [Folder](data/folder).

## How to run this stage
### Prerequisites

Workload Identity setup between the folder factory gitlab repositories and the GCP Identity provider configured with a service account containing required permissions to create folders and their organizational policies. There is a sample code provided in “folder.yaml.sample” to create a folder and for terraform to create a folder minimum below permissions are required.
“Folder Creator” or “Folder Admin” at org level
“Organization Policy Admin” at org level


### Installation Steps

Step 1: Create a bucket for terraform backend on the GCP environment.
Step 2: Create Jenkins Pipeline on Jenkins.
Step 3: Configure the below variables on Jenkins Credentials.

### Terraform config validator
The pipeline has an option to utilise the integrated config validator (gcloud terraform vet) to impose constraints on your terraform configuration. You have to provide the policy-library repo URL to $POLICY_LIBRARY_REPO variable. See the below for details on the Variables to be set on the CI/CD pipeline.


| Variable | | Example Value |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------- |
| PROJECT_NAME | The project containing the service account that has permission to communicate with the WIF provider. Should be created as part of Project Factory. | jenkins-connect-prj |
| GCP_PROJECT_NUMBER | Project number for the project that hosts the WIF provider | 107999111999 |
| SERVICE_ACCOUNT_NAME | The name of the service account that will be used to deploy. Must be hosted in PROJECT_NAME. | jenkins-sa |
| BUCKET_PATH | A state bucket that will hold the terraform state. This bucket must previously exist and the service account must have permission to read/write to it. | jenkins-gcs-state-bucket-name |
| policy_file_path | https://github.com/GoogleCloudPlatform/policy-library | The public repo where the policies are hosted |
| workload_identity_pool_id | | jenkins-test-pool |
| workload_identity_provider_id | | jenkins-test-provider | |

* Once the prerequisites are set up, any commit to the remote main branch with changes to *.tf, *.tfvars, data/*, modules/* files should trigger the pipeline.


### Pipeline Workflow Overview
The complete workflow comprises of 6 stages and 2 before-script jobs
* Stages:
* Clean workspace : This step cleans the previous packages from Jenkins workspace
* WIF : Execute the Workload Identity Federation script and generate credential file.
* Terraform plan: Runs terraform plan and saves the plan and json version of the plan as artifacts, this depends on the branch
* Terraform validate: Runs gcloud terraform vet against the terraform code with the constraints in the specified repository.
* apply: This is executed for specified list of branches, currently main/master

49 changes: 49 additions & 0 deletions examples/guardrails/project-factory/Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
pipeline {
agent any
environment {
BUCKET_PATH = credentials('backend-path')
policy_file_path = credentials('policy_file_path')
}
options {
skipDefaultCheckout(true)
}
stages {
stage('clean workspace') {
steps {
cleanWs()
}
}
stage('checkout') {
steps {
checkout scm
}
}
stage('Terraform Plan') {
steps {
sh '''
cd guardrails/project-factory
terraform init -backend-config="bucket=${BUCKET_PATH}" -backend-config="prefix=project-factory-staging-tfstate" -var-file="staging.tfvars"
terraform plan -var-file="staging.tfvars" -out pfjenkins.tfplan
'''
}
}
stage('Terraform Validate') {
steps {
sh '''
cd guardrails/project-factory
terraform show -json "pfjenkins.tfplan" > "ffjenkins.json"
gcloud source repos clone gcp-policies "${policy_file_path}" --project="${GCP_PROJECT_NUMBER}"
gcloud beta terraform vet "pfjenkins.json" --policy-library="${policy_file_path}" --project="${GCP_PROJECT_NUMBER}"
'''
}
}
stage('Terraform Apply') {
steps {
sh '''
cd guardrails/project-factory
terraform apply -var-file="staging.tfvars" -auto-approve
'''
}
}
}
}
42 changes: 42 additions & 0 deletions examples/guardrails/project-factory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,45 @@ repo_branch: dev
```

Every project is defined with its own file located in the [Project Folder](data/projects).

## How to run this stage
### Prerequisites

Workload Identity setup between the folder factory gitlab repositories and the GCP Identity provider configured with a service account containing required permissions to create folders and their organizational policies. There is a sample code provided in “folder.yaml.sample” to create a folder and for terraform to create a folder minimum below permissions are required.
“Folder Creator” or “Folder Admin” at org level
“Organization Policy Admin” at org level


### Installation Steps

Step 1: Create a bucket for terraform backend on the GCP environment.
Step 2: Create Jenkins Pipeline on Jenkins.
Step 3: Configure the below variables on Jenkins Credentials.

### Terraform config validator
The pipeline has an option to utilise the integrated config validator (gcloud terraform vet) to impose constraints on your terraform configuration. You have to provide the policy-library repo URL to $POLICY_LIBRARY_REPO variable. See the below for details on the Variables to be set on the CI/CD pipeline.


| Variable | | Example Value |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------- |
| PROJECT_NAME | The project containing the service account that has permission to communicate with the WIF provider. Should be created as part of Project Factory. | jenkins-connect-prj |
| GCP_PROJECT_NUMBER | Project number for the project that hosts the WIF provider | 107999111999 |
| SERVICE_ACCOUNT_NAME | The name of the service account that will be used to deploy. Must be hosted in PROJECT_NAME. | jenkins-sa |
| BUCKET_PATH | A state bucket that will hold the terraform state. This bucket must previously exist and the service account must have permission to read/write to it. | jenkins-gcs-state-bucket-name |
| policy_file_path | https://github.com/GoogleCloudPlatform/policy-library | The public repo where the policies are hosted |
| workload_identity_pool_id | | jenkins-test-pool |
| workload_identity_provider_id | | jenkins-test-provider | |

* Once the prerequisites are set up, any commit to the remote main branch with changes to *.tf, *.tfvars, data/*, modules/* files should trigger the pipeline.


### Pipeline Workflow Overview
The complete workflow comprises of 6 stages and 2 before-script jobs
* Stages:
* Clean workspace : This step cleans the previous packages from Jenkins workspace
* WIF : Execute the Workload Identity Federation script and generate credential file.
* Terraform plan: Runs terraform plan and saves the plan and json version of the plan as artifacts, this depends on the branch
* Terraform validate: Runs gcloud terraform vet against the terraform code with the constraints in the specified repository.
* apply: This is executed for specified list of branches, currently main/master


7 changes: 4 additions & 3 deletions examples/guardrails/project-factory/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ module "project" {
source = "./modules/project_plus"
for_each = local.projects
team = each.key
repo_sub = "${each.value.repo_provider == "gitlab" ? "project_path:${each.value.repo_name}:ref_type:branch:ref:${each.value.repo_branch}" : "repo:${each.value.repo_name}:ref:refs/heads/${each.value.repo_branch}"}"
repo_sub = each.value.repo_branch
repo_provider = each.value.repo_provider
billing_account = each.value.billing_account_id
folder = var.folder
roles = try(each.value.roles, [])
wif-pool = "${each.value.repo_provider == "gitlab" ? google_iam_workload_identity_pool.wif-pool-gitlab.name : google_iam_workload_identity_pool.wif-pool-github.name}"
depends_on = [google_iam_workload_identity_pool.wif-pool-github,google_iam_workload_identity_pool.wif-pool-gitlab]
wif-pool = google_iam_workload_identity_pool.wif-pool-jenkins.name
depends_on = [google_iam_workload_identity_pool.wif-pool-jenkins]
}

Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ resource "google_service_account" "sa" {
resource "google_service_account_iam_member" "sa-iam" {
service_account_id = google_service_account.sa.name
role = "roles/iam.workloadIdentityUser"
member = "principalSet://iam.googleapis.com/${var.wif-pool}/attribute.sub/${var.repo_sub}"
member = "principalSet://iam.googleapis.com/${var.wif-pool}/attribute.branch_name/${var.repo_sub}"
}

resource "google_project_iam_member" "sa-project" {
Expand Down
8 changes: 8 additions & 0 deletions examples/guardrails/project-factory/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@
variable "folder" {

}
variable "billing_account" {
}
variable "issuer_uri" {
}

variable "allowed_audiences" {
type = list
}
40 changes: 12 additions & 28 deletions examples/guardrails/project-factory/wif.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,46 +22,30 @@ module "wif-project" {
source = "./modules/project"
name = "wif-prj-${random_id.rand.hex}"
parent = var.folder
billing_account = "01B3B2-962224-4EEC67"
billing_account = var.billing_account
}

resource "google_iam_workload_identity_pool" "wif-pool-gitlab" {
resource "google_iam_workload_identity_pool" "wif-pool-jenkins" {
provider = google-beta
workload_identity_pool_id = "gitlab-pool-${random_id.rand.hex}"
workload_identity_pool_id = "jenkins-pool1-${random_id.rand.hex}"
project = module.wif-project.project_id
}

resource "google_iam_workload_identity_pool_provider" "wif-provider-gitlab" {
resource "google_iam_workload_identity_pool_provider" "wif-provider-jenkins" {
provider = google-beta
workload_identity_pool_id = google_iam_workload_identity_pool.wif-pool-gitlab.workload_identity_pool_id
workload_identity_pool_provider_id = "gitlab-provider-${random_id.rand.hex}"
workload_identity_pool_id = google_iam_workload_identity_pool.wif-pool-jenkins.workload_identity_pool_id
workload_identity_pool_provider_id = "jenkins-provider-${random_id.rand.hex}"
project = module.wif-project.project_id
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.sub" = "assertion.sub"
"attribute.branch_name" = "assertion.branchName"
}
oidc {
issuer_uri = "https://gitlab.com"
}
}

resource "google_iam_workload_identity_pool" "wif-pool-github" {
provider = google-beta
workload_identity_pool_id = "github-pool-${random_id.rand.hex}"
project = module.wif-project.project_id
}

resource "google_iam_workload_identity_pool_provider" "wif-provider-github" {
provider = google-beta
workload_identity_pool_id = google_iam_workload_identity_pool.wif-pool-github.workload_identity_pool_id
workload_identity_pool_provider_id = "github-provider-${random_id.rand.hex}"
project = module.wif-project.project_id
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.sub" = "assertion.sub"
"attribute.actor" = "assertion.actor"
}
oidc {
issuer_uri = "https://token.actions.githubusercontent.com"
issuer_uri = var.issuer_uri
allowed_audiences = var.allowed_audiences
}
depends_on = [
google_iam_workload_identity_pool.wif-pool-jenkins
]
}
Loading