Wenn man bestimmte Prozesse automatisieren möchte kommt es vor, dass z.B. Konfigurationsdateien aus einem Git(lab)-Repo ausgecheckt, angepasst und anschließend automatisch wieder zurück gepusht werden sollen.
Deploy-Keys erstellen
Deploy im Gitlab sind nichts anderes als SSH-Keys, welche dediziert für ein bestimmtes Projeklt verwendet werden können.
Daher ist der erste Schritt die Erstellung neuer SSH-Keys, vorzugsweise mit einem Algorithmus welcher Elliptische Kurven verwendet (z.B. ecdsa
)
Beispiel:
ssh-keygen -t ecdsa -b 521
Hierbei sollte ein entsprechendes Schlüsselpaar erstellt worden sein.
id_ecdsa
ist der private Schlüsselid_ecdsa.pub
ist der öffentliche Schlüssel
Deploykey im Gitlab hinterlegen
Im entsprechenden Projekt kann man unter Einstellungen
—> Repository
—> Deploy Keys
den öffentlichen Schlüssel unter einen eindeutigen Namen hinterlegen und auch Schreibzugriff gewähren. Da man damit seine Änderungen in das Gitlab pushen möchte sollte also Schreibzugriff gewährt werden.
Diesen neuen Deploy Key findet man nun in der entsprechenden Liste.
der private Schlüssel im Playbook?
Es empfiehlt sich nie den privaten Schlüssel als Klartext im Ansible-Playbook einzutragen, da dieser volle Rechte über das entsprechende Repository gewährt.
Von daher sollte der private Schlüssel mit ansible-vault
verschlüsselt werden.
Zu dieser Thematik haben wir bereits einen passenden Artikel verfasst: Sensible Daten verschlüsseln mit Ansible-Vault
Das Passwort um den String wieder zu entschlüsseln kann z.B. beim Jenkins im Jenkins-eigenen Passwort-Store abgelegt werden und die ID mit vaultCredentialsId
an das Playbook übergeben werden.
git Verbindung per Ansible-Playbook
Hierfür müssen verschiedene Sachen festgelegt werden. Ich verwende z.B. für die verschiedenen Variablen eine eigene Datei (group_vars/all.yml
), in welcher die notwendigen Parameter für git
festgelegt sind.
Beipsiel:
---
GIT_URL_PREFIX: "git@git.domain.tld"
GIT_AUTHOR_USER: 'automatic_job'
GIT_AUTHOR_EMAIL: 'admin@domain.tld'
GIT_SSH_WRAPPER: "{{ playbook_dir }}/files/ssh_wrapper.sh"
GIT_PRIVATE_KEYFILE: "{{ playbook_dir }}/files/git_dinge_tun_key.key"
GIT_PRIVATE_KEY: !vault |
$ANSIBLE_VAULT;1.1;AES256
36343666353839373266613665363666373862353333383532626134363137646139303335666638
3236623239636261303639356638343564623463356436320a336261663563643737613933386533
64313630386430666136313339656161356536366238333830653236373566363836343835643531
3031646231333131390a363336373264623839363066346339303933353839376132333463313866
62623435656561636132313731303261316533353561383462326234613838353339393462303065
66613963623634356262373735363164303164373139396432393062326662383937323637666531
31636166383933393864623963623934303963653036316132653866333065373163626461626163
32303234616463333161303461653031323038353034366633643565303761646438626139643665
61323836386663353564383435366636393161636261656363356663373866303538636135333166
39303831363635653165343231376436633331616234346336313635666532326166613233633666
36353266383135373437326633653861386135336466633431376137356137643866666239633162
62326633623133333839336536613561313930626236326532663763353630373163376332313037
38653436613733376533636333323138616232363063353262336135393230653834666232306235
36613638376134623761386137353939333232663034333230386637383136333132363034623931
32626564646434343365383661613161356237626531306333373334346662336164313035326465
36376638663333323365303062356566623934666261636463643033626638616135303235353730
64316432613137386339366365313561353366346463613462346234366637663238643532383334
65623264343939613863323361633439353463666563666430653762363863313366306134313231
37393539313532306235656466383266633731633033343033393263376164303435663737376630
66346166356231373064633962363030386564346531363336646237626464366539326364333037
37353062303332666661363135363666636461333361323538376537616531356365353832386666
32386233373364316465336131636131363839393530646163666662326463623338393461656533
35353265333934313634303465396266393534373934623838613262633562363163316233363736
31653532326630333433
Hier werden die notwendigen Angaben für Author und Mail angegeben, welche git benötigt, aber auch den Namen des privaten Schlüssels (git_dinge_tun_key.key
), welcher noch per ansible-vault
verschlüsselt ist und temporär bei der Ausführung des Jobs auf die Platte geschrieben wird.
Als weiteres sollte man entsprechende Enviroment
Variablen für git
direkt setzen…
- name: "Konfiguration auslesen"
hosts: localhost
connection: local
gather_facts: False
environment:
# as environment because the 'git' executable reads it
GIT_SSH: "{{ GIT_SSH_WRAPPER }}"
# as environment because ssh_wrapper reads it
GIT_KEY: "{{ GIT_PRIVATE_KEYFILE}}"
Aufgrund der etwas älteren git
Version verwende ich noch einen SSH-Wrapper (/files/ssh_wrapper.sh
), welcher folgenden Inhalt hat:
#!/usr/bin/env bash
#
# This wrapper is needed for git versions prior to 2.3, as they
# do not read the GIT_KEY, or GIT_SSH_COMMAND environment variables.
# They only read the GIT_SSH environment variable, with an executable
# for ssh
#
ssh -i "${GIT_KEY}" -o IdentitiesOnly=yes "$@"
Der nun folgende Task erstellt temporär den privaten SSH-Key:
- name: git commit/push"
block:
- name: "Erstelle git ssh keyfile"
copy:
content: "{{ GIT_PRIVATE_KEY }}"
dest: "{{ GIT_PRIVATE_KEYFILE }}"
mode: '0400'
Nun kann z.B. das gewünschte Repo geklont und bearbeitet werden. Ich habe das in diesem Beispiel bereits getan und das Repo in ein temporäres Verzeichnis geklont, welcher Ansible unter der Variable tmpdir.path
bekannt ist.
Anschließend kommt das git add
mit anschließender Ausgabe:
- name: "adding changes to local repository"
shell:
cmd: "git add files/*"
chdir: "{{ tmpdir.path }}/testprojekt"
register: git_add
- name: "Ausgabe git add"
debug:
msg: "{{ git_add.stdout }}"
per loop werden weitere Vorbereitungen getroffen:
- name: "prepare repository for commit and push"
git_config:
scope: local
repo: "{{ tmpdir.path }}/testprojekt"
name: "{{ item.key }}"
value: "{{ item.value }}"
with_dict: {
"user.name": "{{ GIT_AUTHOR_USER }}",
"user.email": "{{ GIT_AUTHOR_EMAIL }}",
}
loop_control:
label: "{{ item.key }}"
Die Änderungen commited:
- name: "commiting changes"
shell:
cmd: "git commit -m 'changes caused by testprojekt: {{ date }}' "
chdir: "{{ tmpdir.path }}/testprojekt"
register: "git_commit"
- debug:
msg: "{{ git_commit }}"
… und gepusht:
- name: "pushing changes to remote"
shell:
cmd: "git push -u origin master"
chdir: "{{ tmpdir.path }}/testprojekt"
register: "git_push"
when: git_add.rc == 0
- debug:
msg: "{{ git_push }}"
da ich diese Tasks als block zusammengefasst habe, kann ich per rescue
bestimmen was im Fehlerfall passieren soll:
Beispiel:
rescue:
- debug:
msg: "Push ins Git fehlgeschlagen"
Des weiteren kann mit der always
Anweisung festlgen, dass der temporär erstellte private SSH-Key wieder gelöscht wird und dabei ist es egal ob die Tasks erfolgreich waren oder nicht.
always:
- name: "cleanup git private key"
file:
state: absent
path: "{{ GIT_PRIVATE_KEYFILE }}"