Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ansible and secrets update #344

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
4e810d5
Remove sites: 100IT and UPV-GRyCAP
enolfc Jun 17, 2024
2b793e8
Remove gone VO
enolfc Jun 17, 2024
1701020
Bring ansible role
enolfc Jun 17, 2024
e6c389f
Not used anymore
enolfc Jun 17, 2024
3f11fe2
Move towards better secret management
enolfc Jun 17, 2024
be47af9
Test the ansible
enolfc Jun 17, 2024
11d7c04
Testing
enolfc Jun 17, 2024
0aa2c33
Debug
enolfc Jun 17, 2024
29b95c3
Black python
enolfc Jun 17, 2024
7d30bf4
Linting
enolfc Jun 17, 2024
16924f0
Fix role
enolfc Jun 17, 2024
785de34
Do not set path for checkout
enolfc Jun 17, 2024
4fd06a2
Debug
enolfc Jun 17, 2024
c2f8af8
Path fixing
enolfc Jun 17, 2024
293279c
Fix path
enolfc Jun 17, 2024
eebb16a
Fix command line
enolfc Jun 17, 2024
9c473ea
Fix role name
enolfc Jun 18, 2024
3881e15
Debug
enolfc Jun 18, 2024
f9bdc4d
More debug
enolfc Jun 18, 2024
d86e4bb
Do not restrict the token
enolfc Jun 18, 2024
e995130
Fix the scope
enolfc Jun 20, 2024
3261850
Fix fedcloud cli invocation
enolfc Jun 20, 2024
c8ee546
Debug
enolfc Jun 20, 2024
151e4e2
Fix cli
enolfc Jun 20, 2024
79f691a
Mask secret
enolfc Jun 20, 2024
c889e97
Let's break things
enolfc Jun 20, 2024
8e27e2c
Fix the deployment
enolfc Jun 21, 2024
a61b7fd
We are not using VO-specific auth now
enolfc Jun 21, 2024
1c44793
Linting
enolfc Jun 21, 2024
0da295f
More debug
enolfc Jun 21, 2024
bf7b930
More debug
enolfc Jun 21, 2024
17ef5ea
Recover the backend config
enolfc Jun 21, 2024
efb753f
Do not rebuild every time
enolfc Jun 21, 2024
b367024
debug
enolfc Jun 21, 2024
97a4f95
Try it another time
enolfc Jun 21, 2024
b0261ec
Fix variable name
enolfc Jun 21, 2024
e248ba3
Debug molecule
enolfc Jun 21, 2024
e3d5480
Revert debugging
enolfc Jun 21, 2024
47c317a
Merge branch 'main' into ansible-secrets
enolfc Jun 21, 2024
116c82d
Move to another molecule action
enolfc Jun 21, 2024
8ec5b1c
Fix path
enolfc Jun 21, 2024
0ce727f
More debug
enolfc Jun 21, 2024
a5ab8f6
Remove example file
enolfc Jun 21, 2024
5c379c7
Tired of testing already :(
enolfc Jun 21, 2024
4da7d6a
Fix file
enolfc Jun 21, 2024
cd59c85
Update python
enolfc Jun 21, 2024
a708ad8
Update image
enolfc Jun 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ jobs:
curl -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 > jq
chmod +x jq
pip install yq git+https://github.com/tdviet/fedcloudclient.git
curl -L https://github.com/oidc-mytoken/client/releases/download/v0.3.0/mytoken_0.3.0_Linux_x86_64.tar.gz \
| tar -xzf -
mkdir ~/.mytoken
curl https://raw.githubusercontent.com/oidc-mytoken/client/master/config/example-config.yaml > ~/.mytoken/config.yaml
- name: Configure providers access
env:
MYTOKEN: ${{ secrets.MYTOKEN }}
REFRESH_TOKEN: ${{ secrets.REFRESH_TOKEN }}
ANSIBLE_SECRETS: ${{ secrets.ANSIBLE_SECRETS }}
run: |
# using parametric scopes to only have access to cloud.egi.eu VO
SCOPE="openid%20email%20profile%20voperson_id"
SCOPE="$SCOPE%20eduperson_entitlement:urn:mace:egi.eu:group:cloud.egi.eu:role=vm_operator#aai.egi.eu"
SCOPE="$SCOPE%20eduperson_entitlement:urn:mace:egi.eu:group:cloud.egi.eu:role=member#aai.egi.eu"
OIDC_TOKEN=$(curl -X POST "https://aai.egi.eu/auth/realms/egi/protocol/openid-connect/token" \
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=token-portal&scope=openid%20email%20profile%20voperson_id%20eduperson_entitlement" \
-d "grant_type=refresh_token&client_id=token-portal&scope=$SCOPE&refresh_token=$REFRESH_TOKEN" \
| jq -r ".access_token")
echo "::add-mask::$OIDC_TOKEN"
cd deploy
Expand All @@ -54,6 +54,12 @@ jobs:
sed -i -e "s/deploy_secret/$DEPLOY_OS_TOKEN/" clouds.yaml
mkdir -p ~/.config/openstack
touch ~/.config/openstack/secure.yaml
FEDCLOUD_LOCKER_TOKEN="$(fedcloud secret locker create \
--oidc-access-token "$OIDC_TOKEN" \
--ttl 1h --num-uses 2)"
echo "::add-mask::$FEDCLOUD_LOCKER_TOKEN"
fedcloud secret put --locker-token "$FEDCLOUD_LOCKER_TOKEN" deploy "data=$ANSIBLE_SECRETS"
echo "FEDCLOUD_LOCKER_TOKEN=$FEDCLOUD_LOCKER_TOKEN" >> "$GITHUB_ENV"
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
Expand All @@ -71,16 +77,13 @@ jobs:
- name: Adjust cloud-init file
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
ANSIBLE_SECRETS: ${{ secrets.ANSIBLE_SECRETS }}
run: |
cd deploy
sed -i -e "s/%TOKEN%/${{ secrets.GITHUB_TOKEN }}/" cloud-init.yaml
sed -i -e "s/%REF%/${{ github.sha }}/" cloud-init.yaml
sed -i -e "s/%SHORT_REF%/$(git rev-parse --short HEAD)/" cloud-init.yaml
sed -i -e "s#%SLACK_WEBHOOK_URL%#$SLACK_WEBHOOK_URL#" cloud-init.yaml
ANSIBLE_ENCODED_SECRETS="$(echo "$ANSIBLE_SECRETS" | base64 -w 0)"
echo "::add-mask::$ANSIBLE_ENCODED_SECRETS"
sed -i -e "s/%ANSIBLE_SECRETS%/$ANSIBLE_ENCODED_SECRETS/" cloud-init.yaml
sed -i -e "s/%FEDCLOUD_LOCKER_TOKEN%/$FEDCLOUD_LOCKER_TOKEN/" cloud-init.yaml
sed -i -e "s/%CLOUDS_YAML%/$(base64 -w 0 < clouds.yaml)/" cloud-init.yaml
- name: terraform plan
id: plan
Expand Down Expand Up @@ -132,19 +135,24 @@ jobs:
terraform output -raw instance-id
- name: Re-configure providers access
env:
MYTOKEN: ${{ secrets.MYTOKEN }}
REFRESH_TOKEN: ${{ secrets.REFRESH_TOKEN }}
run: |
# using parametric scopes to only have access to cloud.egi.eu VO
SCOPE="openid%20email%20profile%20voperson_id"
SCOPE="$SCOPE%20eduperson_entitlement:urn:mace:egi.eu:group:cloud.egi.eu:role=vm_operator#aai.egi.eu"
SCOPE="$SCOPE%20eduperson_entitlement:urn:mace:egi.eu:group:cloud.egi.eu:role=member#aai.egi.eu"
OIDC_TOKEN=$(curl -X POST "https://aai.egi.eu/auth/realms/egi/protocol/openid-connect/token" \
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=token-portal&scope=openid%20email%20profile%20voperson_id%20eduperson_entitlement" \
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=token-portal&scope=$SCOPE" \
| jq -r ".access_token")
echo "::add-mask::$OIDC_TOKEN"
cd deploy
git checkout -- clouds.yaml
BACKEND_SITE="$(yq -r .clouds.backend.site clouds.yaml)"
BACKEND_VO="$(yq -r .clouds.backend.vo clouds.yaml)"
BACKEND_OS_TOKEN="$(fedcloud openstack token issue --oidc-access-token "$OIDC_TOKEN" \
--site "$BACKEND_SITE" --vo "$BACKEND_VO" -j | jq -r '.[0].Result.id')"
echo "::add-mask::$BACKEND_OS_TOKEN"
echo "BACKEND_OS_TOKEN=$BACKEND_OS_TOKEN" >> "$GITHUB_ENV"
sed -i -e "s/backend_secret/$BACKEND_OS_TOKEN/" clouds.yaml
mkdir -p ~/.config/openstack
touch ~/.config/openstack/secure.yaml
Expand All @@ -156,10 +164,9 @@ jobs:
max_attempts: 20
retry_wait_seconds: 40
command: >
set -x &&
pushd deploy &&
openstack --os-cloud backend object save fedcloud-catchall "${{ steps.terraform-vm-id.outputs.stdout }}" &&
openstack --os-cloud backend object delete fedcloud-catchall "${{ steps.terraform-vm-id.outputs.stdout }}"
openstack --os-cloud backend --os-token "$BACKEND_OS_TOKEN" object save fedcloud-catchall "${{ steps.terraform-vm-id.outputs.stdout }}" &&
openstack --os-cloud backend --os-token "$BACKEND_OS_TOKEN" object delete fedcloud-catchall "${{ steps.terraform-vm-id.outputs.stdout }}"
- name: Look for errors
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/molecule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: Test role

on: [push, pull_request]

jobs:
molecule:
name: Runs molecule for the ansible role
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '>=3.9'
- name: Install dependencies
run: |
pip install molecule molecule-plugins[docker] pytest pytest-testinfra
- name: Test Ansible Bootstrap
run: |
cd deploy/roles/catchall
molecule test
env:
PY_COLORS: 1
6 changes: 4 additions & 2 deletions deploy/cloud-init.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ packages:
- ansible
- jq
- python3-openstackclient
- python3-pip
- python3.10-venv
- retry

write_files:
Expand All @@ -40,14 +42,14 @@ write_files:
SLACK_WEBHOOK_URL="%SLACK_WEBHOOK_URL%"
COMMIT_SHA="%REF%"
SHORT_COMMIT_SHA="%SHORT_REF%"
FEDCLOUD_LOCKER_TOKEN="%FEDCLOUD_LOCKER_TOKEN%"

# get the repo code and untar at cwd
curl -L -H "Accept: application/vnd.github.v3+raw" \
"https://api.github.com/repos/EGI-Federation/fedcloud-catchall-operations/tarball/$COMMIT_SHA" | \
tar xz --strip=1
cd deploy
echo "%ANSIBLE_SECRETS%" | base64 -d > ./secrets.yaml
./deploy.sh "$OAUTH_TOKEN" "$COMMIT_SHA" \
./deploy.sh "$OAUTH_TOKEN" "$COMMIT_SHA" "$FEDCLOUD_LOCKER_TOKEN" \
"$SHORT_COMMIT_SHA" "$SLACK_WEBHOOK_URL"
path: /var/lib/cloud/scripts/per-boot/deploy.sh
permissions: '0755'
Expand Down
20 changes: 15 additions & 5 deletions deploy/deploy.sh
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
#!/bin/sh
# Configure current host with ansible
# Expects as arguments the OAUTH_TOKEN, the COMMIT_SHA and the SLACK_WEBHOOK_URL

# Expects as arguments:
# - a GitHub OAUTH_TOKEN to update the PR
# - the COMMIT_SHA
# - a locker for fedcloud secret to obtain the secrets
# - the SHORT_SHA used for pulling the docker image to use
# - a SLACK_WEBHOOK_URL to report on the status
set -e

OAUTH_TOKEN="$1"
COMMIT_SHA="$2"
SHORT_SHA="$3"
SLACK_WEBHOOK_URL="$4"
FEDCLOUD_SECRET_LOCKER="$3"
SHORT_SHA="$4"
SLACK_WEBHOOK_URL="$5"

# create a virtual env for fedcloudclient
python3 -m venv "$PWD/.venv"
"$PWD/.venv/bin/pip" install fedcloudclient

ansible-galaxy install git+https://github.com/EGI-Federation/ansible-role-fedcloud-ops.git
"$PWD/.venv/bin/fedcloud" secret get --locker-token "$FEDCLOUD_SECRET_LOCKER" \
deploy data >secrets.yaml

echo "cloud_info_image: \"ghcr.io/egi-federation/fedcloud-cloud-info:sha-$SHORT_SHA\"" >>extra-vars.yaml

Expand Down
2 changes: 1 addition & 1 deletion deploy/playbook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
- hosts: all
become: true
roles:
- role: ansible-role-fedcloud-ops
- role: catchall
tags: ["all", "docker"]
vars:
site_config_dir: ../sites/
Expand Down
22 changes: 22 additions & 0 deletions deploy/roles/catchall/defaults/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# AMS details
ams_project: egi_cloud_info
ams_host: msg.argo.grnet.gr
ams_token: secret

# check-in endpoint
checkin_token_endpoint: "https://aai.egi.eu/oidc/token"

# docker image for the cloud info provider
cloud_info_image: egifedcloud/ops-cloud-info:latest

# site configuration location
site_config_dir: sites

# No site information as default
sites: []

cloud_info_cron:
minute: "4,34"
hour: "*"
weekday: "*"
timeout: "600"
28 changes: 28 additions & 0 deletions deploy/roles/catchall/molecule/default/converge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
- name: Converge
hosts: all
tasks:
- name: "Include catchall role"
ansible.builtin.include_role:
name: "catchall"
vars:
sites:
- endpoint: https://example.com:5000/v3/
gocdb: foo.bar
vos:
- auth:
project_id: a123456
name: sample_vo
- auth:
project_id: b987659
name: vo.example.com
- endpoint: https://site.org:5000/v3/
gocdb: bar.foo
region: region1
vos:
- auth:
project_id: a123456
name: sample_vo
- auth:
project_id: b987659
name: vo.example.com
13 changes: 13 additions & 0 deletions deploy/roles/catchall/molecule/default/molecule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: instance
image: ubuntu:latest
lint: ansible-lint --exclude .github/
provisioner:
name: ansible
verifier:
name: testinfra
30 changes: 30 additions & 0 deletions deploy/roles/catchall/molecule/default/tests/test_default.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import hashlib
import os

import testinfra.utils.ansible_runner

testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ["MOLECULE_INVENTORY_FILE"]
).get_hosts("all")


def test_site_files(host):
endpoint_hash = hashlib.md5(b"https://example.com:5000/v3/").hexdigest()
filename = "foo-bar-%s" % endpoint_hash
assert host.file("/etc/egi/cloud-info/").is_directory
assert host.file("/etc/egi/cloud-info/%s.yaml" % filename).exists
assert not host.file("/etc/egi/cloud-info/%s.env" % filename).contains("OS_REGION")
assert host.file("/etc/egi/cloud-info/%s.env" % filename).exists
assert host.file("/etc/cron.d/cloud-info-%s" % filename).exists


def test_site_files_region(host):
endpoint_hash = hashlib.md5(b"https://site.org:5000/v3/").hexdigest()
filename = "bar-foo-%s" % endpoint_hash
assert host.file("/etc/egi/cloud-info/").is_directory
assert host.file("/etc/egi/cloud-info/%s.yaml" % filename).exists
assert host.file("/etc/egi/cloud-info/%s.env" % filename).exists
assert host.file("/etc/egi/cloud-info/%s.env" % filename).contains(
"OS_REGION=region1"
)
assert host.file("/etc/cron.d/cloud-info-%s" % filename).exists
4 changes: 4 additions & 0 deletions deploy/roles/catchall/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
molecule
molecule-plugins[docker]
pytest-testinfra
ansible-lint
26 changes: 26 additions & 0 deletions deploy/roles/catchall/tasks/cloud-info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
- name: Cloud-info config directory
ansible.builtin.template:
src: site-info.yaml.j2
dest: /etc/egi/cloud-info/{{ filename }}.yaml
mode: "600"

- name: Cloud info env
ansible.builtin.template:
src: cloud-info.env.j2
dest: /etc/egi/cloud-info/{{ filename }}.env
mode: "600"

- name: Cloud info cron
ansible.builtin.cron:
name: cloud-info-provider {{ site.gocdb }}
weekday: "{{ cloud_info_cron.weekday }}"
minute: "{{ cloud_info_cron.minute }}"
hour: "{{ cloud_info_cron.hour }}"
user: root
job: >
flock -n -w {{ cloud_info_cron.timeout }} /var/lock/cloud-info/{{ filename }}
docker run --rm -v /etc/egi:/etc/egi:ro
--env-file /etc/egi/cloud-info/{{ filename }}.env
{{ cloud_info_image }} >> /var/log/cloud-info/{{ filename }}.log 2>&1
cron_file: "cloud-info-{{ filename }}"
59 changes: 59 additions & 0 deletions deploy/roles/catchall/tasks/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
- name: Install dependencies
ansible.builtin.apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg-agent
- software-properties-common
state: present
update_cache: true

- name: Docker repo key
ansible.builtin.apt_key:
id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
url: https://download.docker.com/linux/ubuntu/gpg
state: present

- name: Add docker repo
ansible.builtin.apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
state: present

- name: Install docker
ansible.builtin.apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
state: present
update_cache: true

- name: Ensure docker config dir is present
ansible.builtin.file:
path: /etc/docker
state: directory
mode: "775"

- name: Configure docker
ansible.builtin.copy:
# this is very CESNET-MCC specific, may be better to move as configurable
content: |
{
"mtu": 1442,
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
dest: /etc/docker/daemon.json
mode: "660"

- name: Restart docker
ansible.builtin.systemd:
name: docker
state: restarted
daemon_reload: true
Loading