Задача — во время выполнения роли скопировать на удалённый хост PEM-ключ.
Для этого используем ansible-vault
.
Идея состоит в том, что мы зашифруем содержимое ключа в переменную, а затем используем модуль copy
— и создадим на удалённой системе новый файл.
Содержание
Создание сертификата
Сначала создадим сам сертификат и приватный ключ с помощью openssl
:
[simterm]
$ openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
[/simterm]
Проверяем содержимое:
[simterm]
$ openssl x509 -text -noout -in certificate.pem Certificate: Data: Version: 3 (0x2) Serial Number: 44:f4:a2:d1:c5:03:a8:f4:78:34:6a:b3:26:45:ef:23:07:dd:a2:34 Signature Algorithm: sha256WithRSAEncryption Issuer: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd Validity Not Before: Feb 5 09:10:00 2019 GMT Not After : Feb 5 09:10:00 2020 GMT Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd ...
[/simterm]
Шифрование данных
Сначала создадим файл, в котором будет храниться пароль для расшифровки данных:
[simterm]
$ cat ~/.ssh/mobilebackend_aws_credentials.yml oigh7fengeiG
[/simterm]
Далее этот файл будет сохранён в Jenkins как Secret file, и будет использоваться для расшифровки данных Ansible:
Создаём второй файл — сюда добавим имя переменной и сам ключ.
Создаём каталог для файлов в роли deploy
:
[simterm]
$ mkdir roles/deploy/files
[/simterm]
Создаём в нём новый файл — apns-{{ env }}.pem.yml
.
В переменную {{ env }}
подставим значение, переданное из group_vars/hostname.yml
, т.е. dev, stage или production:
[simterm]
$ cat group_vars/mobilebackend-dev.yml | grep -w env env: "dev"
[/simterm]
Вызываем ansible-vault
с опцией create
, указываем путь к файлу с паролем:
[simterm]
$ ansible-vault create roles/deploy/files/apns-dev.pem.yml --vault-password-file ~/.ssh/mobilebackend_aws_credentials.yml
[/simterm]
Откроется окно редактирования, вносим имя переменной и значение:
Сохраняем и закрываем файл — и Ansible зашифрует его:
[simterm]
$ head -5 roles/deploy/files/apns-dev.pem.yml $ANSIBLE_VAULT;1.1;AES256 63313035646361303936636338313837353133623461363661363232316361623662316366343833 3335363539653530396336663936653262663534663339360a316364326335306562306666373737 31646538303038613063613837383231633039626561626666353338653662633661613230656463 3731653433383932330a353538323664633337653638393563343132626430663131373738653035
[/simterm]
Если надо отредактировать файл после создания — используем edit
:
[simterm]
$ ansible-vault edit roles/deploy/files/apns-dev.pem.yml --vault-password-file ~/.ssh/mobilebackend_aws_credentials.yml
[/simterm]
Другой вариант — сначала создать plaintext-файл roles/deploy/files/apns-dev.pem.yml
, а потом зашифровать его с помощью encrypt
:
[simterm]
$ ansible-vault encrypt roles/deploy/files/apns-dev.pem.yml --vault-password-file ~/.ssh/mobilebackend_aws_credentials.yml
[/simterm]
Ansible copy
Последним шагом остаётся добавить задачу копирования файла.
Разбиваем её на две части — в одной используем include_vars
, в получаем значение переменной из roles/deploy/files/apns-dev.pem.yml
, во второй — создадим на удалённой системе новый файл с текстом из переменной apns_certificate_key
.
Проверяем возможность прочитать переменную вообще.
Тут Ansible вызывается скриптом из поста AWS: миграция RTFM 3.0 (final) – CloudFormation и Ansible роли, в котором есть функция ansible_exec()
:
... ansible_exec () { local tags=$1 local env=$2 local vault=$3 local rsa=$4 local connection=$5 local application=$6 ansible-playbook --private-key $rsa --tags "$1" --limit=$env mobilebackend.yml --vault-password-file $vault --extra-vars "$connection $application" } ...
Запускаем, проверяем:
[simterm]
$ ./ansible_exec.sh -t deploy Tags: deploy Env: mobilebackend-dev Vault: /home/setevoy/.ssh/mobilebackend_aws_credentials.yml RSA: /home/setevoy/Work/example/aws-credentials/bm-backend-dev.pem APP: Are you sure to proceed? [y/n] y ... TASK [deploy : Check certificate content] **** ok: [dev.backend-app2-internal.example.world] => { "msg": "Certificate body: -----BEGIN PRIVATE KEY-----\nMII***LJH\n-----END PRIVATE KEY-----\n" ...
[/simterm]
Хорошо — переменная считалась, тело сертификата получили — добавляем задачу с copy
:
... - name: "Deploy APNS certificate" copy: dest: "/data/projects/{{ backend_project_name }}/common/config/apns-certificate.pem" content: "{{ apns_certificate_key }}" owner: "{{ backend_project_name }}" group: "{{ backend_project_name }}" mode: 0400 when: "'yoga' in backend_project_name and 'console' in inventory_hostname" ...
Тут в dest
указываем путь на удалённой системе, а в content
— подставляем значение из переменной apns_certificate_key
.
Задаём пользователя, группу и права — {{ backend_project_name }}
и права 400.
В условии when
проверяем какой проект деплоится, т.к. создавать ключи нам надо только для проекта «yoga» и на хосте в имени которого есть слово console (dev.backend-console-internal.example.world) в переменной inventory_hostname
.
Имя проекта передаётся через переменную APP_PROJECT_NAME
джобы в Jenkins, и считывается в плейбуке проекта:
... - role: deploy tags: deploy backend_prodject_git_branch: "{{ lookup('env','APP_REPO_BRANCH') }}" backend_project_git_repo: "{{ lookup('env','APP_REPO_RUL') }}" backend_project_name: "{{ lookup('env','APP_PROJECT_NAME') }}" when: "'backend-bastion' not in inventory_hostname"
Сейчас задаём переменную вручную:
[simterm]
$ export APP_PROJECT_NAME=yoga
[/simterm]
Запускаем:
[simterm]
... TASK [deploy : Read APNS certificate from the apns-dev.pem.yml] **** ok: [dev.backend-app1-internal.example.world] skipping: [dev.backend-bastion.examplee.world] ok: [dev.backend-app2-internal.example.world] ok: [dev.backend-console-internal.example.world] TASK [deploy : Check certificate content] **** ok: [dev.backend-app1-internal.example.world] => { "msg": "Certificate body: -----BEGIN PRIVATE KEY-----\nMII***LJH\n-----END PRIVATE KEY-----\n" } ... TASK [deploy : Deploy APNS certificate] **** ... skipping: [dev.backend-bastion.example.world] changed: [dev.backend-console-internal.example.world] ...
[/simterm]
Проверяем на удалённом хосте наличие файла, пользователя и права доступа:
[simterm]
root@bttrm-dev-console:/home/admin/Scripts# ll /data/projects/yoga/common/config/apns-certificate.pem -r-------- 1 yoga yoga 1704 Feb 5 12:06 /data/projects/yoga/common/config/apns-certificate.pem
[/simterm]
И содержимое:
[simterm]
root@bttrm-dev-console:/home/admin/Scripts# head -5 /data/projects/yoga/common/config/apns-certificate.pem -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCziHZIiFYYriVb hRWDN2cR5j6wHpK3+CEc2rXl+Umc6m8el/jcJX3uVIckfmFfsapvpSO3MD0gkhKI knJw48rhUlk3FUsTF7/pmstYIAxu7APc5nphiTt6YyNlp8L1xc0tKCuxSvcLDmR8 OiMbGE5Rm9EXXi4E6UAibFe9VQfZSsle9pzZCC+lDD4Rh1TLjOju/w4fnXprXkDY
[/simterm]
Готово.