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

Testing Cloud Provisioning with Terraform and InSpec

Testing Cloud Provisioning with Terraform and InSpec

This talks looks into Terraform and InSpec and how they can be combined effectively.

https://www.continuouslifecycle.de

Christoph Hartmann

November 15, 2018
Tweet

More Decks by Christoph Hartmann

Other Decks in Technology

Transcript

  1. @chri_hartmann
    Testing Cloud
    Provisioning with
    Terraform and InSpec
    Christoph Hartmann

    View Slide

  2. @chri_hartmann
    Christoph Hartmann
    Co-Creator InSpec & Dev-Sec.io Project
    Engineering Director
    Twitter: @chri_hartmann
    Github: chris-rock

    View Slide

  3. @chri_hartmann
    Assumptions
    ● You use a tool like Terraform for your deployments
    ● You agree on infrastructure as code
    ● You agree that code should be tested
    ● How can we combine Terraform with testing?

    View Slide

  4. @chri_hartmann
    Agenda
    ● Challenges with High-Velocity Deployments
    ● Manage changes safely over time
    ● Ensure that your deployments are configured securely
    ● Summary

    View Slide

  5. @chri_hartmann
    High-Velocity Deployments
    QUALITY/COMPLIANCE
    RATE OF INNOVATION
    ● How do you automate your
    deployment?
    ● How do I introduce changes and
    updates safely?
    ● How do I make sure deployment
    updates are reliable?

    View Slide

  6. Deployment Setup
    Provisioning Verification

    View Slide

  7. @chri_hartmann
    Plan Deployment
    $ terraform plan -out plan.out
    Refreshing Terraform state in-memory prior to plan...
    The refreshed state will be used to calculate this plan, but will not be
    persisted to local or remote state storage.
    ...
    Plan: 7 to add, 0 to change, 0 to destroy.
    ------------------------------------------------------------------------
    This plan was saved to: plan.out
    To perform exactly these actions, run the following command to apply:
    terraform apply "plan.out"

    View Slide

  8. @chri_hartmann
    Execute Deployment
    $ terraform apply plan.out
    digitalocean_ssh_key.key: Creating...
    fingerprint: "" => ""
    name: "" => "Terraform Example"
    ...
    Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
    Outputs:
    Id = 118465877
    Load Balancer Public ip = 178.128.139.19
    Name = nginx-web-ams3
    Public ip = 206.189.101.99

    View Slide

  9. @chri_hartmann

    View Slide

  10. @chri_hartmann
    Verify Deployment
    $ terraform plan
    Refreshing Terraform state in-memory prior to plan...
    The refreshed state will be used to calculate this plan, but will not be
    persisted to local or remote state storage.
    null_resource.inspec: Refreshing state... (ID: 917976163460846921)
    digitalocean_ssh_key.key: Refreshing state... (ID: 23510906)
    digitalocean_tag.web: Refreshing state... (ID: inspec-web)
    digitalocean_certificate.web: Refreshing state... (ID: 8a81fce0-9788-417d-92bf-4c7d5e37ecca)
    digitalocean_loadbalancer.public: Refreshing state... (ID: a5d6877e-7360-49b8-95ee-fdd128540ac1)
    digitalocean_droplet.crown: Refreshing state... (ID: 118465875)
    digitalocean_droplet.web: Refreshing state... (ID: 118465877)
    ------------------------------------------------------------------------
    No changes. Infrastructure is up-to-date.
    This means that Terraform did not detect any differences between your
    configuration and real physical resources that exist. As a result, no
    actions need to be performed.

    View Slide

  11. @chri_hartmann
    Change Firewall Rules

    View Slide

  12. @chri_hartmann
    Change Firewall Rules

    View Slide

  13. @chri_hartmann
    Change Firewall Rules
    $ terraform plan
    ...
    ------------------------------------------------------------------------
    An execution plan has been generated and is shown below.
    Resource actions are indicated with the following symbols:
    ~ update in-place
    Terraform will perform the following actions:
    ~ digitalocean_firewall.web
    inbound_rule.1029929102.port_range: "80" => "80"
    inbound_rule.1029929102.protocol: "tcp" => "tcp"
    inbound_rule.1029929102.source_addresses.#: "2" => "2"
    inbound_rule.1029929102.source_addresses.217649824: "0.0.0.0/0" => "0.0.0.0/0"
    inbound_rule.1029929102.source_addresses.4017721845: "::/0" => "::/0"
    inbound_rule.1029929102.source_droplet_ids.#: "0" => "0"
    inbound_rule.1029929102.source_load_balancer_uids.#: "0" => "0"

    View Slide

  14. @chri_hartmann
    Terraform found the change!

    View Slide

  15. @chri_hartmann
    There are shortcoming ...
    ● It can only test what is part of the deployment
    ● It can only do positive testing
    ● It is not testing the instances, or provisioned services itself

    View Slide

  16. @chri_hartmann
    InSpec turns infrastructure testing, compliance
    and security requirements into code

    View Slide

  17. @chri_hartmann
    Test: Documentation
    SSH supports two different protocol versions. The original version, SSHv1, was
    subject to a number of security issues. Please use SSHv2 instead to avoid
    these.

    View Slide

  18. @chri_hartmann
    Test: InSpec
    describe sshd_config do
    its('Protocol') { should eq('2') }
    end

    View Slide

  19. @chri_hartmann
    Test: Inspec + Metadata
    control 'sshd-10' do
    impact 1.0
    title 'Server: Specify protocol version 2'
    desc "Only SSH protocol version 2 connections
    should be permitted. Version 1 of the
    protocol contains security vulnerabilities.
    Don't use legacy insecure SSHv1 connections
    anymore."
    describe sshd_config do
    its('Protocol') { should eq('2') }
    end
    end

    View Slide

  20. @chri_hartmann
    Shared Testing Tooling & Language
    SECURITY
    DEVOPS
    COMPLIANCE

    View Slide

  21. @chri_hartmann
    Verify the provisioned infra with InSpec

    View Slide

  22. Deployment Setup
    Provisioning Verification

    View Slide

  23. @chri_hartmann
    Verify instances
    describe http('http://0.0.0.0/') do
    its('status') { should eq 200 }
    its('body') { should match /InSpec landing<\/title>/ }
    end

    View Slide

  24. @chri_hartmann
    Verify instances

    View Slide

  25. @chri_hartmann
    InSpec Operating System Support
    Amazon Linux CentOS HP UX
    IBM AIX RHEL SLES Ubuntu Windows
    Debian
    Cisco IOS

    View Slide

  26. @chri_hartmann
    Verify cloud security
    control 'only use https' do
    title 'verify that only https is used for load balancers'
    only_if { digitalocean_loadbalancers.exists? }
    digitalocean_loadbalancers.forwarding_rules.flatten.each { |rule|
    describe rule do
    its('entry_protocol') { should eq 'https' }
    its('entry_port') { should eq 443 }
    end
    }
    end

    View Slide

  27. @chri_hartmann
    Verify cloud security

    View Slide

  28. Deployment Setup
    Provisioning Verification

    View Slide

  29. @chri_hartmann
    Let’s do this again

    View Slide

  30. @chri_hartmann
    InSpec Terraform Provisioner

    View Slide

  31. @chri_hartmann
    Verify Instance Deployment
    resource "digitalocean_droplet" "web" {
    ...
    provisioner "inspec" {
    profiles = [
    "https://github.com/chris-rock/testing-4-cloud/blob/do_droplet_profile-0.1.0.tar.gz?raw=true",
    "supermarket://dev-sec/linux-baseline",
    "supermarket://dev-sec/ssh-baseline",
    ]
    reporter {
    name = "cli"
    }
    connection {
    type = "ssh"
    private_key = "${file("./id_rsa")}"
    user = "root"
    timeout = "2m"
    }
    on_failure = "continue"
    }
    }

    View Slide

  32. @chri_hartmann
    Verify Cloud Deployment
    resource "null_resource" "inspec" {
    // runs inspec profile against digitial ocean cloud services
    provisioner "inspec" {
    profiles = [
    "../do-security-profile",
    ]
    target {
    backend = "digitalocean"
    }
    reporter {
    name = "cli"
    }
    // we allow failures for now
    on_failure = "continue"
    }
    }

    View Slide

  33. @chri_hartmann
    Verify Cloud Deployment
    droplet = attribute('digitalocean_droplet.web')
    loadbalancer = attribute('digitalocean_loadbalancer.public')
    describe digitalocean_droplet(id: droplet['id']) do
    it { should exist }
    its('name') { should eq 'nginx-web-ams3' }
    its('image') { should eq 'ubuntu-16-04-x64' }
    its('region') { should eq 'ams3' }
    its('size') { should eq 's-1vcpu-1gb' }
    end
    describe digitalocean_loadbalancer(name: 'loadbalancer-1') do
    it { should exist }
    its('name') { should eq 'loadbalancer-1' }
    its('status') { should eq 'active' }
    its('algorithm') { should eq 'round_robin' }
    its('ip') { should eq loadbalancer['ip'] }
    end

    View Slide

  34. Deployment Setup
    Provisioning Verification

    View Slide

  35. @chri_hartmann
    What to validate?
    Concern Terrafrom InSpec
    Type of instance requested ✔ ✔
    Verify instances ✗ ✔
    All instances are part of an app ✗ ✔
    Security groups are correct ✔ ✔
    No security group allows world
    access
    ✗ ✔
    Load Balancer is setup correctly ✔ ✔
    Ensure only one load balancer is used ✗ ✔

    View Slide

  36. @chri_hartmann
    Bonus: Zero Downtime Updates
    Ensure new infrastructure is created before the old is destroyed
    resource "digitalocean_droplet" "web" {
    ...
    lifecycle {
    create_before_destroy = true
    }
    }
    https://www.hashicorp.com/blog/zero-downtime-updates-with-terraform

    View Slide

  37. @chri_hartmann
    Bonus: Zero Downtime Updates
    Ensure instances are deployed properly:
    resource "digitalocean_droplet" "web" {

    provisioner "inspec" {
    profiles = [
    "https://profiles/do_droplet_profile-0.1.0.tar.gz",
    "supermarket://dev-sec/linux-baseline",
    "supermarket://dev-sec/ssh-baseline",
    ]
    lifecycle {
    create_before_destroy = true
    }
    }
    https://www.hashicorp.com/blog/zero-downtime-updates-with-terraform

    View Slide

  38. All successfully tested with Terraform and InSpec
    Provisioning Verification

    View Slide

  39. InSpec’s Extension Mechanism
    CLI and Platform
    Plugins
    Terraform Provisioner
    Plugin
    terraform plugin github: inspec/terraform-provisioner-inspec
    inspec terraform cli plugin github: inspec/inspec-iggy

    View Slide

  40. @chri_hartmann
    Cloud Platform Support
    ● InSpec is integrated in Azure Shell and part of Azure Policy's Guest
    Configuration
    ● InSpec is Integrated into AWS EC2 Run Command
    ● InSpec integrates with PowerClI

    View Slide

  41. @chri_hartmann
    New: Support for Google Cloud Platform
    github: inspec/inspec-gcp

    View Slide

  42. InSpec’s Extension Mechanism (Current)
    My CIS L1
    (inspec overlay)
    CIS Lvl1
    (inspec)
    DevSec Windows
    Patch
    Baseline
    DevSec Linux
    Baseline
    DevSec Windows
    Baseline
    DevSec Linux Patch
    Baseline
    Profile 1 Profile 2
    Resource Pack
    Profile Inheritance Wrapper Profiles Resource Packs

    View Slide

  43. InSpec helps to shift security concerns to the left
    Compliance
    DevOps

    View Slide

  44. @chri_hartmann
    Wrap-up
    ● You’ve seen how Terraform and InSpec work hand-in-hand
    ● The approach works with AWS, Azure, GCP etc as well.
    ● It makes your cloud deployments more reliable
    ● By combining Terraform with InSpec, you can ensure deployments
    are secure
    ● It’s easy to verify instance provisioning during a Terraform run
    ● Bonus: It helps to align DevOps, Security and Compliance teams

    View Slide

  45. @chri_hartmann
    OpenSource Resources
    inspec.io
    • Hands on tutorials
    • Extensive documentation
    • Code examples
    dev-sec.io
    • Chef Cookbooks
    • InSpec Baselines

    View Slide