---

- hosts: localhost
  connection: local
  gather_facts: no
  vars_files:
    - vars/ec2_security_groups.yaml
  vars:
    vault_role_name: vault
  tasks:
    # TODO(jph): This uses attributes not available until Ansible 2.2.
    #- name: configure vault IAM role
    #  iam:
    #    iam_type: role
    #    name: "{{ vault_role_name }}"
    #    # NOTE: Roles cannot be updated, only created and deleted!
    #    state: present
    #    trust_policy:
    #      Version: "2012-10-17"
    #      Statement:
    #        - Action: sts:AssumeRole
    #          Effect: Allow
    #          Principal:
    #            Service: ec2.amazonaws.com
    # TODO(jph): This runs into syntax issues in Ansible 2.1:
    # https://github.com/ansible/ansible-modules-core/issues/3404
    #- name: configure vault IAM policy
    #  iam_policy:
    #    iam_type: role
    #    iam_name: "{{ vault_role_name }}"
    #    region: us-west-1
    #    state: present

    #    policy_name: vault-dynamodb-access
    #    policy_json:
    #      Version: "2012-10-17"
    #      Statement:
    #        - Action:
    #          - "dynamodb:*"
    #          Effect: Allow
    #          Resource: "*"

    - name: provision production vault hosts
      ec2:
        exact_count: 1
        count_tag:
          Role: vault_server

        image: ami-84423ae4 # Ubuntu 16.04 LTS
        instance_type: t2.micro
        region: us-west-1

        instance_tags:
          Role: vault_server
          Name: vault server
        key_name: vault
        instance_profile_name: "{{ vault_role_name }}"
        vpc_subnet_id: subnet-27140b42 # vault private us-west-1a
        group_id:
          - sg-d1f770b5 # vault
        assign_public_ip: no
        private_ip: 10.1.13.4
        termination_protection: yes

        volumes:
          - device_name: /dev/sda1
            volume_size: 30
            delete_on_termination: yes

        wait: yes
      register: ec2
    # This allows us to immediately configure these servers, despite not being
    # part of the tag at the start of the run.
    - name: add newly-provisioned servers to host group
      add_host: hostname={{ item.private_ip }} groups=vault_hosts
      with_items: '{{ ec2.instances }}'
    - name: wait for provisioned servers to start ssh
      wait_for:
        host: "{{ item.private_ip }}"
        port: 22
      with_items: '{{ ec2.instances }}'
    - name: accept new ssh fingerprints
      shell: ssh-keyscan -H {{ item.private_ip }} >> ~/.ssh/known_hosts
      with_items: '{{ ec2.instances }}'

    - name: vault security group
      ec2_group:
        name: vault
        description: .
        vpc_id: '{{ vpc.vpc_default }}'
        region: us-west-1
        rules:
          - proto: tcp
            from_port: '{{ ports.ssh }}'
            to_port: '{{ ports.ssh }}'
            cidr_ip: '{{ cidr.corp.all }}'
          - proto: tcp
            from_port: '{{ ports.vault }}'
            to_port: '{{ ports.vault }}'
            cidr_ip: '{{ cidr.corp.all }}'
          - proto: tcp
            from_port: '{{ ports.vault }}'
            to_port: '{{ ports.vault }}'
            cidr_ip: '{{ cidr.eng.all }}'

    - name: configure dynamodb storage backend
      dynamodb_table:
        name: vault-dynamodb-backend
        region: us-west-1
        read_capacity: 5
        write_capacity: 1
        # The hash key helps Amazon partition tables across instances, and
        # should generally be well distributed.  'Key' fits that well, and is
        # what Vault uses when it creates a new table.
        hash_key_name: Key
        hash_key_type: STRING

# Get the base Ansible dependencies working on any newly-booted machines.
- hosts: vault_hosts
  # Fact-gathering requires the standard Ansible dependencies.
  gather_facts: no
  tasks:
    - include: tasks/bootstrap_ansible_dependencies.yaml

- hosts: tag_Role_vault_server:vault_hosts
  roles:
    - role: sshd
      sshd:
        # See sshd_config(5) for descriptions of these options.
        AllowUsers: ubuntu
        PasswordAuthentication: no
        PermitEmptyPasswords: no
        PermitRootLogin: no
        Protocol: 2
        StrictModes: yes
    - role: vault-server
    - role: prometheus-exporter

- hosts: localhost
  connection: local
  gather_facts: no
  vars_files:
    - vars/vault.yaml
  tasks:
    # It would be nice to use something idempotent for these.  Like
    # https://github.com/sidick/ansible_vault , but we'll probably have to
    # support it ourselves.
    - name: configure Vault for AD auth
      command: >
        vault write auth/ldap/config
          url='ldap://corp.zooxlabs.com'
          binddn="CN=Service Vault,OU=ServiceAccounts,OU=Users,OU=ZOOX,DC=corp,DC=zooxlabs,DC=com"
          bindpass='{{ vault_ad_password }}'
          userattr=sAMAccountName
          userdn="OU=Software,OU=Users,OU=ZOOX,DC=corp,DC=zooxlabs,DC=com"
          groupattr="cn"
          groupdn="OU=Security Groups,OU=ZOOX,DC=corp,DC=zooxlabs,DC=com"
          groupfilter="(&(objectClass=group))"

    - name: mount AWS secret backends
      # 'vault mount' complains if you try to mount at a mountpoint that's
      # already in use, so this includes a poor-man's idempotentcy check.
      # This has to be on one line due to
      # https://github.com/ansible/ansible/issues/20993
      shell: vault mounts | grep --silent --fixed-strings 'aws/{{ item }}' || vault mount -path='aws/{{ item }}' aws
      with_items:
        - us-west-1
      register: mounts_output
      changed_when: mounts_output.stdout
    - name: configure Vault AWS secret backend
      command: >
        vault write aws/us-west-1/config/root
          access_key=AKIAITQBHU6GZUK6PJ2A
          secret_key='{{ vault_aws_secret_key }}'
          region=us-west-1

    - name: set up VaultUsers group
      command: vault write auth/ldap/groups/VaultUsers policies=VaultUsers
    - name: set up VaultUsers policy
      command: vault policy write VaultUsers files/policies/VaultUsers.hcl

    - name: retrieve Vault audit backends
      command: vault audit list
      register: audit_backends
      changed_when: false
      # When there are no backends configured, audit-list returns 1.
      failed_when: (audit_backends.rc != 0 and
                    'No audit backends are enabled.' not in audit_backends.stderr)
    - name: configure Vault audit backend
      command: vault audit enable file file_path=/var/log/vault/audit.log
      when: '"/var/log/vault/audit.log" not in audit_backends.stdout'
