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

Read-only service accounts for automation and CI/CD #1899

Merged
merged 67 commits into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
efcc4c1
add design doc for the new CI/CD sa
ludoo Dec 3, 2023
a28b312
describe the actual implementation
ludoo Dec 3, 2023
3efb95c
specify which files will need to be changed
ludoo Dec 3, 2023
4c3df9a
Update 0-cicd-plan-sa.md
ludoo Dec 3, 2023
6103798
Update 0-cicd-plan-sa.md
ludoo Dec 3, 2023
99e0e91
Update 0-cicd-plan-sa.md
ludoo Dec 3, 2023
bd15403
Update 0-cicd-plan-sa.md
ludoo Dec 3, 2023
6a604a8
Update 0-cicd-plan-sa.md
ludoo Dec 3, 2023
30dcfb8
Update 0-cicd-plan-sa.md
ludoo Dec 3, 2023
4b6702f
Update 0-cicd-plan-sa.md
ludoo Dec 3, 2023
c918b0b
Fix typo
wiktorn Dec 3, 2023
d08f432
stage 0 read-only service accounts
ludoo Dec 3, 2023
3f6b3c6
Merge branch 'ludo/fast-cicd-permissions' of github.com:GoogleCloudPl…
ludoo Dec 3, 2023
c6a8b03
Merge branch 'master' into ludo/fast-cicd-permissions
ludoo Dec 3, 2023
57fcb16
stage 0 IAM map
ludoo Dec 3, 2023
ddaae28
linting
ludoo Dec 3, 2023
8543e03
cicd read-only service accounts
ludoo Dec 4, 2023
0750c73
tweak workflow templates
ludoo Dec 4, 2023
59352b8
roles and github workflow fixes
ludoo Dec 4, 2023
87db86c
tfdoc
ludoo Dec 4, 2023
849b870
Merge branch 'master' into ludo/fast-cicd-permissions
ludoo Dec 5, 2023
40e27eb
Ad-hoc custom role factory for FAST bootstrap
juliocc Dec 5, 2023
c09f1fb
Merge branch 'master' into ludo/fast-cicd-permissions
ludoo Dec 5, 2023
c838242
use factory variable for custom roles data path
ludoo Dec 5, 2023
b5588da
custom roles factory in org/project modules
ludoo Dec 5, 2023
abbf26d
tfdoc
ludoo Dec 5, 2023
e7165dd
rename custom roles factory variable, fix gitlab template
ludoo Dec 6, 2023
d869618
gitlab workflow fixes
ludoo Dec 6, 2023
c07d129
Merge remote-tracking branch 'origin/master' into ludo/fast-cicd-perm…
ludoo Dec 9, 2023
5a08c1f
Merge remote-tracking branch 'origin/master' into ludo/fast-cicd-perm…
ludoo Dec 12, 2023
e74ec7c
fix merge
ludoo Dec 12, 2023
e9b4f22
Merge branch 'master' into ludo/fast-cicd-permissions
ludoo Dec 13, 2023
e66ba6a
output plan results on failed assertion
ludoo Dec 13, 2023
c9b8389
update stage 0 expected values
ludoo Dec 13, 2023
06560d0
data platform branch
ludoo Dec 13, 2023
f49830a
Merge remote-tracking branch 'origin/master' into ludo/fast-cicd-perm…
ludoo Dec 18, 2023
2d9acfc
Merge remote-tracking branch 'origin/master' into ludo/fast-cicd-perm…
ludoo Dec 18, 2023
7df23b5
gke
ludoo Dec 18, 2023
ae6aaab
networking
ludoo Dec 18, 2023
8865235
security
ludoo Dec 18, 2023
ef0120e
project factory
ludoo Dec 18, 2023
9f7dae9
outputs
ludoo Dec 18, 2023
af247ad
workflow templates
ludoo Dec 18, 2023
97b8978
resman apply fixes
ludoo Dec 18, 2023
05a4598
tfdoc
ludoo Dec 18, 2023
e80a263
fix stage 1 test fixture
ludoo Dec 18, 2023
c0bccf6
fix gh workflow
ludoo Dec 18, 2023
42df43c
read-only resman sa roles
ludoo Dec 18, 2023
3c471b4
fix test
ludoo Dec 18, 2023
611ad89
read-only resman sa roles
ludoo Dec 18, 2023
164856a
read-only resman sa roles
ludoo Dec 18, 2023
499a93d
Merge branch 'master' into ludo/fast-cicd-permissions
ludoo Dec 19, 2023
226a934
read-only resman sa roles
ludoo Dec 19, 2023
0c4bc5e
read-only resman sa roles
ludoo Dec 19, 2023
54c7d83
fix test variables
ludoo Dec 19, 2023
1f4d5a8
Merge branch 'ludo/fast-cicd-permissions' of github.com:GoogleCloudPl…
ludoo Dec 19, 2023
87579ba
Merge branch 'master' into ludo/fast-cicd-permissions
ludoo Dec 19, 2023
1194e53
Merge remote-tracking branch 'origin/master' into ludo/fast-cicd-perm…
ludoo Dec 22, 2023
b4eeda7
rename wif principal attribute names
ludoo Dec 22, 2023
8d83230
rename wif principal variables
ludoo Dec 22, 2023
4766f56
multitenant stages
ludoo Dec 25, 2023
c815608
Merge branch 'master' into ludo/fast-cicd-permissions
ludoo Dec 25, 2023
94cb258
Merge branch 'master' into ludo/fast-cicd-permissions
ludoo Dec 27, 2023
5009d02
Merge branch 'master' into ludo/fast-cicd-permissions
ludoo Dec 27, 2023
6e48f95
fix r/o provider names for stage 2s and 3s
ludoo Dec 27, 2023
7ac64c8
align gitlab token expiration with github
ludoo Dec 27, 2023
ac0e324
align gitlab token expiration with github
ludoo Dec 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
105 changes: 71 additions & 34 deletions fast/assets/templates/workflow-github.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ on:
- synchronize

env:
FAST_OUTPUTS_BUCKET: ${outputs_bucket}
FAST_SERVICE_ACCOUNT: ${service_account}
FAST_SERVICE_ACCOUNT: ${service_accounts.apply}
FAST_SERVICE_ACCOUNT_PLAN: ${service_accounts.plan}
FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
TF_PROVIDERS_FILE: ${tf_providers_file}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}
TF_VERSION: 1.4.4
TF_PROVIDERS_FILE: ${tf_providers_files.apply}
TF_PROVIDERS_FILE_PLAN: ${tf_providers_files.plan}
TF_VERSION: 1.6.5

jobs:
fast-pr:
Expand All @@ -46,60 +46,82 @@ jobs:
uses: actions/checkout@v3

# set up SSH key authentication to the modules repository

- id: ssh-config
name: Configure SSH authentication
run: |
ssh-agent -a "$SSH_AUTH_SOCK" > /dev/null
ssh-add - <<< "$${{ secrets.CICD_MODULES_KEY }}"

# set up authentication via Workload identity Federation
# set up step variables for plan / apply

- id: vars-plan
if: github.event.pull_request.merged != true && success()
name: Set up plan variables
run: |
echo "plan_opts=-lock=false" >> "$GITHUB_ENV"
echo "provider_file=$${{env.TF_PROVIDERS_FILE_PLAN}}" >> "$GITHUB_ENV"
echo "service_account=$${{env.FAST_SERVICE_ACCOUNT_PLAN}}" >> "$GITHUB_ENV"

- id: vars-apply
if: github.event.pull_request.merged == true && success()
name: Set up apply variables
run: |
echo "provider_file=$${{env.TF_PROVIDERS_FILE}}" >> "$GITHUB_ENV"
echo "service_account=$${{env.FAST_SERVICE_ACCOUNT}}" >> "$GITHUB_ENV"

# set up authentication via Workload identity Federation and gcloud

- id: gcp-auth
name: Authenticate to Google Cloud
uses: google-github-actions/auth@v0
uses: google-github-actions/auth@v2
with:
workload_identity_provider: $${{ env.FAST_WIF_PROVIDER }}
service_account: $${{ env.FAST_SERVICE_ACCOUNT }}
access_token_lifetime: 3600s
workload_identity_provider: $${{env.FAST_WIF_PROVIDER}}
service_account: $${{env.service_account}}
access_token_lifetime: 900s
ludoo marked this conversation as resolved.
Show resolved Hide resolved

- id: gcp-sdk
name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v0
uses: google-github-actions/setup-gcloud@v2
with:
install_components: alpha

# copy provider and tfvars files
- id: tf-config
name: Copy Terraform output files
# copy provider file

- id: tf-config-provider
name: Copy Terraform provider file
run: |
gcloud alpha storage cp -r \
"gs://$${{env.FAST_OUTPUTS_BUCKET}}/providers/$${{env.TF_PROVIDERS_FILE}}" ./
"gs://${outputs_bucket}/providers/$${{env.provider_file}}" ./
%{~ for f in tf_var_files ~}
gcloud alpha storage cp -r \
"gs://$${{env.FAST_OUTPUTS_BUCKET}}/tfvars" ./
for f in $${{env.TF_VAR_FILES}}; do
ln -s "tfvars/$f" ./
done
"gs://${outputs_bucket}/tfvars/${f}" ./
%{~ endfor ~}

- id: tf-setup
name: Set up Terraform
uses: hashicorp/setup-terraform@v2.0.3
with:
terraform_version: $${{ env.TF_VERSION }}
terraform_version: $${{env.TF_VERSION}}

# run Terraform init/validate/plan

- id: tf-init
name: Terraform init
continue-on-error: true
run: |
terraform init -no-color

- id: tf-validate
continue-on-error: true
name: Terraform validate
run: terraform validate -no-color

- id: tf-plan
name: Terraform plan
continue-on-error: true
run: |
terraform plan -input=false -out ../plan.out -no-color
terraform plan -input=false -out ../plan.out -no-color $${{env.plan_opts}}

- id: tf-apply
if: github.event.pull_request.merged == true && success()
Expand All @@ -108,28 +130,31 @@ jobs:
run: |
terraform apply -input=false -auto-approve -no-color ../plan.out

# PR comment with Terraform result from previous steps
# length is checked and trimmed for length so as to stay within the limit

- id: pr-comment
name: Post comment to Pull Request
continue-on-error: true
uses: actions/github-script@v6
if: github.event_name == 'pull_request'
env:
PLAN: $${{ steps.tf-plan.outputs.stdout }}\n$${{ steps.tf-plan.outputs.stderr }}
PLAN: $${{steps.tf-plan.outputs.stdout}}\n$${{steps.tf-plan.outputs.stderr}}
with:
script: |
const output = `### Terraform Initialization \`$${{ steps.tf-init.outcome }}\`
const output = `### Terraform Initialization \`$${{steps.tf-init.outcome}}\`

### Terraform Validation \`$${{ steps.tf-validate.outcome }}\`
### Terraform Validation \`$${{steps.tf-validate.outcome}}\`

<details><summary>Validation Output</summary>

\`\`\`\n
$${{ steps.tf-validate.outputs.stdout }}
$${{steps.tf-validate.outputs.stdout}}
\`\`\`

</details>

### Terraform Plan \`$${{ steps.tf-plan.outcome }}\`
### Terraform Plan \`$${{steps.tf-plan.outcome}}\`

<details><summary>Show Plan</summary>

Expand All @@ -139,9 +164,9 @@ jobs:

</details>

### Terraform Apply \`$${{ steps.tf-apply.outcome }}\`
### Terraform Apply \`$${{steps.tf-apply.outcome}}\`

*Pusher: @$${{ github.actor }}, Action: \`$${{ github.event_name }}\`, Working Directory: \`$${{ env.tf_actions_working_dir }}\`, Workflow: \`$${{ github.workflow }}\`*`;
*Pusher: @$${{github.actor}}, Action: \`$${{github.event_name}}\`, Working Directory: \`$${{env.tf_actions_working_dir}}\`, Workflow: \`$${{github.workflow}}\`*`;

github.rest.issues.createComment({
issue_number: context.issue.number,
Expand All @@ -151,22 +176,22 @@ jobs:
})

- id: pr-short-comment
name: Post comment to Pull Request
name: Post comment to Pull Request (abbreviated)
uses: actions/github-script@v6
if: github.event_name == 'pull_request' && steps.pr-comment.outcome != 'success'
with:
script: |
const output = `### Terraform Initialization \`$${{ steps.tf-init.outcome }}\`
const output = `### Terraform Initialization \`$${{steps.tf-init.outcome}}\`

### Terraform Validation \`$${{ steps.tf-validate.outcome }}\`
### Terraform Validation \`$${{steps.tf-validate.outcome}}\`

### Terraform Plan \`$${{ steps.tf-plan.outcome }}\`
### Terraform Plan \`$${{steps.tf-plan.outcome}}\`

Plan output is in the action log.

### Terraform Apply \`$${{ steps.tf-apply.outcome }}\`
### Terraform Apply \`$${{steps.tf-apply.outcome}}\`

*Pusher: @$${{ github.actor }}, Action: \`$${{ github.event_name }}\`, Working Directory: \`$${{ env.tf_actions_working_dir }}\`, Workflow: \`$${{ github.workflow }}\`*`;
*Pusher: @$${{github.actor}}, Action: \`$${{github.event_name}}\`, Working Directory: \`$${{env.tf_actions_working_dir}}\`, Workflow: \`$${{github.workflow}}\`*`;

github.rest.issues.createComment({
issue_number: context.issue.number,
Expand All @@ -175,6 +200,18 @@ jobs:
body: output
})

# exit on error from previous steps

- id: check-init
name: Check init failure
if: steps.tf-init.outcome != 'success'
run: exit 1

- id: check-validate
name: Check validate failure
if: steps.tf-validate.outcome != 'success'
run: exit 1

- id: check-plan
name: Check plan failure
if: steps.tf-plan.outcome != 'success'
Expand Down
143 changes: 59 additions & 84 deletions fast/assets/templates/workflow-gitlab.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,113 +12,88 @@
# See the License for the specific language governing permissions and
# limitations under the License.

default:
image:
name: hashicorp/terraform
entrypoint:
- "/usr/bin/env"
- "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

variables:
GOOGLE_CREDENTIALS: cicd-sa-credentials.json
FAST_OUTPUTS_BUCKET: ${outputs_bucket}
FAST_SERVICE_ACCOUNT: ${service_account}
FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
%{~ if tf_providers_file != "" ~}
TF_PROVIDERS_FILE: ${tf_providers_file}
%{~ if tf_var_files != [] ~}
TF_VAR_FILES: ${join("\n ", tf_var_files)}
%{~ endif ~}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}

workflow:
rules:
# merge / apply
- if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
variables:
COMMAND: apply
FAST_SERVICE_ACCOUNT: ${service_accounts.apply}
TF_PROVIDERS_FILE: 0-bootstrap-providers.tf
# pr / plan
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
variables:
COMMAND: plan
FAST_SERVICE_ACCOUNT: ${service_accounts.plan}
TF_PROVIDERS_FILE: 0-bootstrap-r-providers.tf

stages:
- gcp-auth
- tf-files
- tf-plan
- tf-apply
- gcp-setup
- tf-plan-apply

cache:
key: gcp-auth
paths:
- cicd-sa-credentials.json
- token.txt
%{~ if tf_providers_file != "" ~}
- ${tf_providers_file}
%{~ endif ~}
%{~ for f in tf_var_files ~}
- ${f}
%{~ endfor ~}
# TODO: document project-level deploy key used to fetch modules

gcp-auth:
gcp-setup:
stage: gcp-setup
image:
name: google/cloud-sdk:slim
artifacts:
paths:
- cicd-sa-credentials.json
- providers.tf
id_tokens:
GITLAB_TOKEN:
aud:
%{~ for aud in audiences ~}
- ${aud}
%{~ endfor ~}
image:
name: google/cloud-sdk:slim
stage: gcp-auth
before_script:
- echo "$GITLAB_TOKEN" > token.txt
script:
- echo "$${GITLAB_TOKEN}" > token.txt
- |
gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \
--service-account=$${FAST_SERVICE_ACCOUNT} \
--service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \
$FAST_WIF_PROVIDER \
--service-account=$FAST_SERVICE_ACCOUNT \
--service-account-token-lifetime-seconds=900 \
--output-file=$GOOGLE_CREDENTIALS \
--credential-source-file=token.txt
- gcloud config set auth/credential_file_override $GOOGLE_CREDENTIALS
- gcloud alpha storage cp -r "gs://$FAST_OUTPUTS_BUCKET/providers/$TF_PROVIDERS_FILE" ./providers.tf

tf-files:
tf-plan-apply:
stage: tf-plan-apply
dependencies:
- gcp-auth
- gcp-setup
id_tokens:
GITLAB_TOKEN:
aud:
%{~ for aud in audiences ~}
- ${aud}
%{~ endfor ~}
image:
name: google/cloud-sdk:slim
stage: tf-files
script:
# - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
%{~ if tf_providers_file != "" ~}
- gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
%{~ endif ~}
%{~ for f in tf_var_files ~}
- gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
%{~ endfor ~}
- ls -l

tf-plan:
dependencies:
- tf-files
stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
# - |
# ssh-agent -a $SSH_AUTH_SOCK > /dev/null
# echo "$CICD_MODULES_KEY" | base64 -d | tr -d '\r' | ssh-add - > /dev/null
# mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
script:
- terraform init
- terraform validate
- terraform plan

tf-apply:
dependencies:
- tf-files
stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
# - |
# ssh-agent -a $SSH_AUTH_SOCK > /dev/null
# echo "$CICD_MODULES_KEY" | base64 -d | tr -d '\r' | ssh-add - > /dev/null
# mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
name: hashicorp/terraform
entrypoint:
- "/usr/bin/env"
variables:
SSH_AUTH_SOCK: /tmp/ssh-agent.sock
script:
- |
ssh-agent -a $SSH_AUTH_SOCK
echo "$CICD_MODULES_KEY" | ssh-add -
mkdir -p ~/.ssh
ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
- echo "$GITLAB_TOKEN" > token.txt
- terraform init
- terraform validate
- terraform apply -input=false -auto-approve
when: manual
only:
variables:
- $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- "if [ $COMMAND == 'plan' ]; then terraform plan -input=false -no-color -lock=false; fi"
- "if [ $COMMAND == 'apply' ]; then terraform apply -input=false -no-color -auto-approve; fi"