Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Increasing the Security Posture of your Pipelines

Increasing the Security Posture of your Pipelines

In this talk, I share lessons learned about increasing the security posture of CI / CD pipelines and how Terraform can help unlock patterns that work at scale.

This version of the talk was given as the opening keynote at devopsdays Ljubljana in September 2023.

Kerim Satirli

September 30, 2023

More Decks by Kerim Satirli

Other Decks in Technology

Transcript

  1. Define the Pipeline ! react to repository events # deal

    with code quality issues " ensure code quality
  2. !!" # when to run this pipeline <trigger> # all

    the stuff it needs to do <steps> # handle errors other people introduced <more steps> pipeline.yml Define the Pipeline
  3. !!" # when to run this pipeline on: push: jobs:

    # all the stuff it needs to do happy_path: steps: - run: terraform fmt -check -recursive !# terraform validate # handle errors other people introduced sad_path: steps: - if: $!$ failure() !% uses: upload-artifacts terraform.yml Define the Pipeline
  4. !!" # when to run this pipeline on: push: jobs:

    # all the stuff it needs to do happy_path: steps: - run: terraform fmt -check -recursive !# terraform validate # handle errors other people introduced sad_path: steps: - if: $!$ failure() !% uses: upload-artifacts terraform.yml Define the Pipeline
  5. !!" # when to run this pipeline on: push: jobs:

    # all the stuff it needs to do happy_path: steps: - run: terraform fmt -check -recursive !# terraform validate with: version: "1.6.0" terraform.yml Define the Pipeline
  6. terraform.yml !!" # when to run this pipeline on: push:

    jobs: # all the stuff it needs to do happy_path: steps: - uses: "hashicorp/setup-terraform" - run: terraform fmt -check -recursive !# terraform validate with: version: "1.6.0" Define the Pipeline
  7. terraform.yml !!" # when to run this pipeline on: push:

    jobs: # all the stuff it needs to do happy_path: steps: - uses: "hashicorp/[email protected]" - run: terraform fmt -check -recursive !# terraform validate with: version: "1.6.0" Define the Pipeline
  8. terraform.yml My Pipeline Definition !!" # when to run this

    pipeline on: push: jobs: # all the stuff it needs to do happy_path: steps: - uses: "hashicorp/[email protected]" - run: terraform fmt -check -recursive !# terraform validate with: version: "1.6.0"
  9. terraform.yml Their Pipeline Definition !!" # when to run this

    pipeline on: push: jobs: # all the stuff it needs to do happy_path: steps: - uses: "hashicorp/setup-terraform@633b725c73b2cacd13a8fdd1" - run: terraform fmt -check -recursive !# terraform validate with: version: "1.6.0"
  10. variables.tf variable "actions_config" { type = map(object({ owner = string

    repository = string version = string })) default = { # see https:!"github.com/hashicorp/setup-terraform/releases terraform = { owner = "hashicorp" repository = "setup-terraform" version = "v2.0.3" } } } Define a Set of Actions
  11. variables.tf data "github_release" "actions" { for_each = { for id,

    action in var.actions_config : id !& action } repository = each.value.repository owner = each.value.owner retrieve_by = "tag" release_tag = each.value.version } data "github_ref" "actions" { for_each. = data.github_release.actions repository = each.value.repository owner = each.value.owner ref = "tags/${each.value.release_tag}" } Retrieve Release Information
  12. variables.tf Transform Release Information locals { actions_config = { #

    This place is not a place of honor. # no highly esteemed deed is commemorated here. # (but we really needed these values) for action in tolist(keys(var.actions_config)) : action !& { owner = var.actions_config[action].owner path = var.actions_config[action].path ref = data.github_ref.actions[action].ref repo = var.actions_config[action].repository sha = data.github_ref.actions[action].sha version = var.actions_config[action].version } } }
  13. Terminal Verify Transformed Data > terraform output github_actions_releases { "terraform"

    = { "repo" = "hashicorp/setup-terraform" "sha" = "633666f66e0061ca3b725c73b2ec20cd13a8fdd1" "version" = "v2.0.3" } }
  14. terraform.tftpl.yml Prepare Template !!' jobs: workflow: name: Terraform runs-on: ubuntu-latest

    steps: # github.com/${owner}/${repo}/releases/tag/${version} - name: Set up Terraform uses: "${owner}/${repo}@${sha}" # ref: `${ref}` with: terraform_version: "1.6.0" !!'
  15. variables.tf Render Template locals { repository_files = [ { file

    = ".github/workflows/terraform.yml" content = templatefile("./tmpl/terraform.tftpl.yml", { checkout = local.actions_config["checkout"] terraform = local.actions_config["terraform"] } ) }, ] }
  16. terraform.yml Render Template !!' jobs: workflow: name: Terraform runs-on: ubuntu-latest

    steps: # github.com/hashicorp/setup-terraform/releases/tag/v2.0.3 - name: Set up Terraform uses: "hashicorp/setup-terraform@633!!'dd1" # ref: `tags/v2.0.3` with: terraform_version: "1.6.0" !!'
  17. organization.tf Update Allow List for Actions resource "github_actions_organization_permissions" "main" {

    allowed_actions = "selected" enabled_repositories = "all" allowed_actions_config { github_owned_allowed = false verified_allowed = false } }
  18. organization.tf Update Allow List for Actions resource "github_actions_organization_permissions" "main" {

    allowed_actions = "selected" enabled_repositories = "all" allowed_actions_config { github_owned_allowed = false verified_allowed = false patterns_allowed = [ for action in local.actions_config : action.path !( null ? "${action.owner}/$ {action.repository}/${action.path}@${action.sha}" : "$ {action.owner}/${action.repository}@${action.sha}" ] } }