TravisCI and Ansible on AWS

If you’re trying to use Travis CI and Ansible playbooks to spin up and configure instances on AWS, you’ll want to do things at some point:

  1. Configure instances on private subnets with Ansible via bastion host
  2. Secure the said Bastion host’s security group to talk to TravisCI

The problem is that Travis CI is a hosted service on the Internet, whereas your instances are sitting in a private subnet inside AWS. How can you make TravisCI use Ansible to talk to these instances? How do you find out TravisCI’s IP address, given that TravisCI launches your build in a new container each time?

The answer lies in Ansible 2.0’s new SSH Jump Host setting. The following lines should be set as variables for the group or host vars. I set it in group_vars/all because that fits my use case currently:

ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o ProxyCommand="ssh -i <private-key-for-bastion-host.pem> -W %h:%p -q ubuntu@X.X.X.X"'
ansible_ssh_private_key_file: '<private-key-for-private-subnet-instances.pem>'

The first variable is appended to SSH commands automatically by Ansible. The problem with Ansible’s documentation is that it doesn’t mention the need to specify the key file for the bastion host, and I spent hours with errors such as these:

debug1: key_load_public: No such file or directory
debug1: identity file /<private-key-file.pub-cert> type -1

It is probably immediately apparent to someone that works with SSH / Ansible day-in and day-out, though.

Next, you should encrypt these private keys with Travis encrypt files command and paste the output of the command into your .travis.yml file, like so:

before_install:
- openssl aes-256-cbc -K $encrypted_23423423_key -iv $encrypted_23423423_iv -in <private-key>.enc -out <private-key>.pem -d

which dynamically decrypts the file during a build into the container’s current directory (which is the directory where it clones your Git repo, for example). If you want to encrypt multiple files, you should encrypt an archive of the files like so: https://docs.travis-ci.com/user/encrypting-files/#Encrypting-multiple-files

Next, let’s talk about securing the security group for the bastion host. Now, you don’t want to open SSH up for the world, do you? But given that TravisCI launches a new container with a different IP each time, how do you open the security group to this container?

The answer is dynamic modification of the security group. This is how I did it in .travis.yml:

- PUBLIC_IP=`wget http://ipecho.net/plain -O - -q ; echo`
- "echo travis_ip: $PUBLIC_IP >> group_vars/all"


script:
- ansible-playbook 01_create.yml

This effectively puts a variable called “travis_ip” into the group_vars/all file that is then picked up by Ansible when it runs the 01_create.yml playbook.

- name: create/maintaing EC2 security group for Bastion host
    local_action:
      module: ec2_group
      name: "{{ bastion_sg }}"
      description: Security Group for Bastion Server
      region: "{{ region }}"
      vpc_id: "{{ vpc_id }}"
      rules:
        - proto: tcp
           from_port: 22
           to_port: 22
           cidr_ip: "{{ travis_ip }}/32"

That’s it! You’re now all set to use Travis CI and Ansible.

This entry was posted in Linux, Tech.. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s