diff --git a/.gitea/actions/setup-ansible-env/action.yml b/.gitea/actions/setup-ansible-env/action.yml new file mode 100644 index 0000000..d906d43 --- /dev/null +++ b/.gitea/actions/setup-ansible-env/action.yml @@ -0,0 +1,99 @@ +name: Setup Ansible Environment +description: Prepare the environment for A13labs CI/CD pipelines +inputs: + access-token: + description: "Bitwarden access token" + required: true + project-id: + description: "Bitwarden project ID" + required: true + organization-id: + description: "Bitwarden organization ID" + required: true + ansible-user: + description: "The user to use for Ansible" + required: true + ssh-auth-socket: + description: "The SSH_AUTH_SOCK environment variable" + default: "/tmp/ssh_agent.sock" + host-group: + description: "The host group to setup the Ansible environment" + default: "public" +outputs: + ssh-auth-sock: + description: "The SSH_AUTH_SOCK environment variable" + value: ${{ steps.start-ssh-agent.outputs.ssh-auth-sock }} + hosts: + description: "The list of hosts in the host group" + value: ${{ steps.read-hosts.outputs.hosts }} + +runs: + using: "composite" + steps: + - name: Install required python packages + shell: bash + run: | + python3 -m pip install -r requirements/ansible.txt + + - name: Prepare SSH key + shell: bash + env: + BW_ACCESS_TOKEN: ${{ inputs.access-token }} + BW_PROJECT_ID: ${{ inputs.project-id }} + BW_ORGANIZATION_ID: ${{ inputs.organization-id }} + run: | + sectool ssh unlock ansible + mkdir -p ~/.ssh + chmod 700 ~/.ssh + cp ssh-keys/ansible/id_ecdsa ~/.ssh/id_ecdsa + chmod 600 ~/.ssh/id_ecdsa + + - name: Read hosts from inventory + id: read-hosts + shell: bash + env: + HOST_GROUP: ${{ inputs.host-group }} + run: | + ansible-inventory -i inventory/hosts --list --yaml --limit $HOST_GROUP | grep -oE '([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}' | sort -u > /tmp/ansible_hosts + echo "hosts=$(cat /tmp/ansible_hosts)" >> $GITEA_OUTPUT + + - name: Read SSH host keys from remote hosts + shell: bash + run: | + mkdir -p ~/.ssh + for HOST in $(cat /tmp/ansible_hosts); do + ssh-keyscan "$HOST" >> ~/.ssh/known_hosts + done + chmod 600 ~/.ssh/known_hosts + + - name: Enable SSH host key algorithms + shell: bash + run: | + echo "Host *" >> ~/.ssh/config + echo " HostKeyAlgorithms +sk-ecdsa-sha2-nistp256@openssh.com, sk-ssh-ed25519@openssh.com" + chmod 600 ~/.ssh/config + + - name: Start SSH agent and add SSH key + id: start-ssh-agent + shell: bash + env: + BW_ACCESS_TOKEN: ${{ inputs.access-token }} + BW_PROJECT_ID: ${{ inputs.project-id }} + BW_ORGANIZATION_ID: ${{ inputs.organization-id }} + SSH_AUTH_SOCK: ${{ inputs.ssh-auth-socket }} + run: | + ssh-agent -a $SSH_AUTH_SOCK > /dev/null + echo 'sectool vault get SSH_PASSWORD' > ~/.ssh_askpass && chmod +x ~/.ssh_askpass + DISPLAY=None SSH_ASKPASS=~/.ssh_askpass ssh-add ~/.ssh/id_ecdsa < /dev/null + rm ~/.ssh_askpass + echo "ssh-auth-sock=$SSH_AUTH_SOCK" >> $GITEA_OUTPUT + + - name: Check SSH Connection to remote hosts + shell: bash + env: + ANSIBLE_USER: ${{ inputs.ansible-user }} + SSH_AUTH_SOCK: ${{ inputs.ssh-auth-socket }} + run: | + for HOST in $(cat /tmp/ansible_hosts); do + ssh "$ANSIBLE_USER@$HOST" echo "SSH connection to "$HOST" successful" + done diff --git a/.gitea/actions/setup-env/action.yml b/.gitea/actions/setup-env/action.yml new file mode 100644 index 0000000..04845d5 --- /dev/null +++ b/.gitea/actions/setup-env/action.yml @@ -0,0 +1,24 @@ +name: Setup Environment +description: Prepare the environment for A13labs CI/CD pipelines +outputs: + changed_files: + description: The list of changed files in the current pull request + value: ${{ steps.get_changed_files.outputs.changed_files }} + +runs: + using: "composite" + steps: + - name: Get changed files + id: get_changed_files + shell: bash + run: | + CHANGED_FILES=$(git diff --name-only ${{ gitea.event.before }} ${{ gitea.sha }}) + echo "changed_files=$CHANGED_FILES" >> $GITEA_OUTPUT + + - name: Setup Sectool + uses: ./.gitea/actions/setup-sectool + + - name: Install Python packages + shell: bash + run: | + python3 -m pip install --upgrade pip diff --git a/.gitea/actions/setup-k8s-env/action.yml b/.gitea/actions/setup-k8s-env/action.yml new file mode 100644 index 0000000..b0b4a89 --- /dev/null +++ b/.gitea/actions/setup-k8s-env/action.yml @@ -0,0 +1,54 @@ +name: Setup K8S Environment +description: Prepare the environment for A13labs CI/CD pipelines +inputs: + access-token: + description: "Bitwarden access token" + required: true + project-id: + description: "Bitwarden project ID" + required: true + organization-id: + description: "Bitwarden organization ID" + required: true + ansible-user: + description: "The user to use for Ansible" + required: true + k8s-target: + description: "The target host to deploy the K8S applications" + default: "microk8s" + ssh-auth-sock: + description: "The SSH_AUTH_SOCK environment variable" + default: "/tmp/ssh_agent.sock" + +runs: + using: "composite" + steps: + - name: Copy Kube Config from remote host + shell: bash + env: + BW_ACCESS_TOKEN: ${{ inputs.access-token }} + BW_PROJECT_ID: ${{ inputs.project-id }} + BW_ORGANIZATION_ID: ${{ inputs.organization-id }} + ANSIBLE_USER: ${{ inputs.ansible-user }} + SSH_AUTH_SOCK: ${{ inputs.ssh-auth-sock }} + K8S_TARGET: ${{ inputs.k8s-target }} + run: | + mkdir -p ~/.kube + ansible -i inventory/hosts -u $ANSIBLE_USER -m fetch -a "src=/home/$ANSIBLE_USER/.kube/config dest=~/.kube/config flat=yes" $K8S_TARGET + + - name: Forward K8S API Server port + shell: bash + env: + BW_ACCESS_TOKEN: ${{ inputs.access-token }} + BW_PROJECT_ID: ${{ inputs.project-id }} + BW_ORGANIZATION_ID: ${{ inputs.organization-id }} + ANSIBLE_USER: ${{ inputs.ansible-user }} + SSH_AUTH_SOCK: ${{ inputs.ssh-auth-sock }} + K8S_TARGET: ${{ inputs.k8s-target }} + run: | + ANSIBLE_HOST=$(ansible -i inventory/hosts -u $ANSIBLE_USER -m shell -a "hostname" $K8S_TARGET | grep -oE '([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}' | head -1) + IP_ADDR=$(ansible -i inventory/hosts -u $ANSIBLE_USER -m shell -a "curl -s ifconfig.me" $K8S_TARGET | grep -oE '([0-9]+\.){3}[0-9]+') + + ssh -f -N -L 16443:localhost:16443 "$ANSIBLE_USER@$ANSIBLE_HOST" + + sed -i "s/server: https:\/\/$IP_ADDR:16443/server: https:\/\/localhost:16443/g" ~/.kube/config diff --git a/.gitea/actions/setup-opentofu-env/action.yml b/.gitea/actions/setup-opentofu-env/action.yml new file mode 100644 index 0000000..bd7f50d --- /dev/null +++ b/.gitea/actions/setup-opentofu-env/action.yml @@ -0,0 +1,19 @@ +name: Setup OpenTofu Environment +description: Prepare the environment for A13labs CI/CD pipelines + +runs: + using: "composite" + steps: + - name: Setup OpenTofu + shell: bash + run: | + TOFU_VERSION="1.9.1" + curl -sL "https://github.com/opentofu/opentofu/releases/download/v${TOFU_VERSION}/tofu_${TOFU_VERSION}_linux_amd64.zip" -o /tmp/tofu.zip + unzip -o /tmp/tofu.zip -d /usr/local/bin + rm /tmp/tofu.zip + tofu version + + - name: Install required python packages + shell: bash + run: | + python3 -m pip install -r requirements/opentofu.txt diff --git a/.gitea/actions/setup-sectool/action.yml b/.gitea/actions/setup-sectool/action.yml new file mode 100644 index 0000000..2828622 --- /dev/null +++ b/.gitea/actions/setup-sectool/action.yml @@ -0,0 +1,16 @@ +name: Setup Sectool +description: Download and install the sectool binary from GitHub releases + +runs: + using: "composite" + steps: + - name: Download sectool binary + shell: bash + run: | + LATEST=$(curl -s https://api.github.com/repos/a13labs/sectool/releases/latest) + ASSET_URL=$(echo "$LATEST" | jq -r '.assets[] | select(.name | test("linux.*x64")) | .browser_download_url') + curl -sL "$ASSET_URL" -o /tmp/sectool.zip + unzip -o /tmp/sectool.zip -d /usr/local/bin + rm /tmp/sectool.zip + chmod +x /usr/local/bin/sectool + sectool version diff --git a/.gitea/workflows/ansible-validate-on-pr.yml b/.gitea/workflows/ansible-validate-on-pr.yml new file mode 100644 index 0000000..8e3a8f8 --- /dev/null +++ b/.gitea/workflows/ansible-validate-on-pr.yml @@ -0,0 +1,37 @@ +name: Ansible Validate On Pull Request +on: + pull_request: + branches: + - main + paths: + - "ansible/**" + types: + - opened + - synchronize + - reopened +jobs: + ansible-validate: + runs-on: cicd-base + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup environment + uses: ./.gitea/actions/setup-env + + - name: Install Python packages + run: | + python3 -m pip install -r requirements/ansible.txt + + - name: Ansible Lint + run: | + cd ansible + ansible-lint . + + - name: Ansible Playbook Syntax Check + run: | + cd ansible + ansible-playbook --syntax-check playbook_*.yml diff --git a/.gitea/workflows/aws-validate-on-pr.yml b/.gitea/workflows/aws-validate-on-pr.yml new file mode 100644 index 0000000..e4ca7c2 --- /dev/null +++ b/.gitea/workflows/aws-validate-on-pr.yml @@ -0,0 +1,39 @@ +name: Terraform AWS IAC Validate on Pull Request + +on: + pull_request: + branches: + - main + paths: + - "terraform/iac/aws/**" + types: + - opened + - synchronize + - reopened +jobs: + iac-validate: + runs-on: cicd-base + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup environment + uses: ./.gitea/actions/setup-env + + - name: Setup OpenTofu environment + uses: ./.gitea/actions/setup-opentofu-env + + - name: OpenTofu Init and Validate + env: + BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }} + BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }} + BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }} + run: | + cd terraform/iac/aws + sectool -f ../../sectool.json exec tofu init + sectool -f ../../sectool.json exec tofu validate + sectool -f ../../sectool.json exec tofu fmt -check + sectool -f ../../sectool.json exec tofu plan diff --git a/.gitea/workflows/cloudns-validate-on-pr.yml b/.gitea/workflows/cloudns-validate-on-pr.yml new file mode 100644 index 0000000..bfb691f --- /dev/null +++ b/.gitea/workflows/cloudns-validate-on-pr.yml @@ -0,0 +1,39 @@ +name: Terraform ClouDNS IAC Validate on Pull Request + +on: + pull_request: + branches: + - main + paths: + - "terraform/iac/cloudns/**" + types: + - opened + - synchronize + - reopened +jobs: + iac-validate: + runs-on: cicd-base + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup environment + uses: ./.gitea/actions/setup-env + + - name: Setup OpenTofu environment + uses: ./.gitea/actions/setup-opentofu-env + + - name: OpenTofu Init and Validate + env: + BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }} + BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }} + BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }} + run: | + cd terraform/iac/cloudns + sectool -f ../../sectool.json exec tofu init + sectool -f ../../sectool.json exec tofu validate + sectool -f ../../sectool.json exec tofu fmt -check + sectool -f ../../sectool.json exec tofu plan diff --git a/.gitea/workflows/contabo-validate-on-pr.yml b/.gitea/workflows/contabo-validate-on-pr.yml new file mode 100644 index 0000000..babaf97 --- /dev/null +++ b/.gitea/workflows/contabo-validate-on-pr.yml @@ -0,0 +1,39 @@ +name: Terraform Contabo IAC Validate on Pull Request + +on: + pull_request: + branches: + - main + paths: + - "terraform/iac/contabo/**" + types: + - opened + - synchronize + - reopened +jobs: + iac-validate: + runs-on: cicd-base + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup environment + uses: ./.gitea/actions/setup-env + + - name: Setup OpenTofu environment + uses: ./.gitea/actions/setup-opentofu-env + + - name: OpenTofu Init and Validate + env: + BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }} + BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }} + BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }} + run: | + cd terraform/iac/contabo + sectool -f ../../sectool.json exec tofu init + sectool -f ../../sectool.json exec tofu validate + sectool -f ../../sectool.json exec tofu fmt -check + sectool -f ../../sectool.json exec tofu plan diff --git a/.gitea/workflows/k8s-apps-validate.yml b/.gitea/workflows/k8s-apps-validate.yml new file mode 100644 index 0000000..00730d5 --- /dev/null +++ b/.gitea/workflows/k8s-apps-validate.yml @@ -0,0 +1,63 @@ +name: OpenTofu K8s Apps Validate on Pull Request + +on: + pull_request: + branches: + - main + paths: + - "terraform/apps/**" + types: + - opened + - synchronize + - reopened +jobs: + iac-validate: + runs-on: cicd-base + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup environment + uses: ./.gitea/actions/setup-env + + - name: Setup Ansible Environment + id: setup_ansible_env + uses: ./.gitea/actions/setup-ansible-env + with: + project-id: ${{ secrets.BW_PROJECT_ID }} + organization-id: ${{ secrets.BW_ORGANIZATION_ID }} + access-token: ${{ secrets.BW_ACCESS_TOKEN }} + ansible-user: ${{ secrets.ANSIBLE_USER }} + host-group: microk8s + + - name: Setup OpenTofu Environment + uses: ./.gitea/actions/setup-opentofu-env + + - name: Setup Kubernetes Environment + uses: ./.gitea/actions/setup-k8s-env + with: + project-id: ${{ secrets.BW_PROJECT_ID }} + organization-id: ${{ secrets.BW_ORGANIZATION_ID }} + access-token: ${{ secrets.BW_ACCESS_TOKEN }} + ansible-user: ${{ secrets.ANSIBLE_USER }} + + - name: OpenTofu Init and Validate + env: + BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }} + BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }} + BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }} + run: | + cd terraform/apps/dev-01 + sectool -f ../../sectool.json exec tofu init + sectool -f ../../sectool.json exec tofu validate + sectool -f ../../sectool.json exec tofu fmt -check + sectool -f ../../sectool.json exec tofu plan + + cd terraform/apps/prod-01 + sectool -f ../../sectool.json exec tofu init + sectool -f ../../sectool.json exec tofu validate + sectool -f ../../sectool.json exec tofu fmt -check + sectool -f ../../sectool.json exec tofu plan diff --git a/.gitea/workflows/scaleway-validate-on-pr.yml b/.gitea/workflows/scaleway-validate-on-pr.yml new file mode 100644 index 0000000..416be0a --- /dev/null +++ b/.gitea/workflows/scaleway-validate-on-pr.yml @@ -0,0 +1,39 @@ +name: Terraform Scaleway IAC Validate on Pull Request + +on: + pull_request: + branches: + - main + paths: + - "terraform/iac/scaleway/**" + types: + - opened + - synchronize + - reopened +jobs: + iac-validate: + runs-on: cicd-base + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup environment + uses: ./.gitea/actions/setup-env + + - name: Setup OpenTofu environment + uses: ./.gitea/actions/setup-opentofu-env + + - name: OpenTofu Init and Validate + env: + BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }} + BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }} + BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }} + run: | + cd terraform/iac/scaleway + sectool -f ../../sectool.json exec tofu init + sectool -f ../../sectool.json exec tofu validate + sectool -f ../../sectool.json exec tofu fmt -check + sectool -f ../../sectool.json exec tofu plan diff --git a/.github/workflows/ansible-validate-playbook-on-pr.yml.disabled b/.github/workflows/ansible-validate-playbook-on-pr.yml.disabled index 250abb6..d938f9d 100644 --- a/.github/workflows/ansible-validate-playbook-on-pr.yml.disabled +++ b/.github/workflows/ansible-validate-playbook-on-pr.yml.disabled @@ -29,7 +29,6 @@ jobs: organization-id: ${{ secrets.BW_ORGANIZATION_ID }} access-token: ${{ secrets.BW_ACCESS_TOKEN }} ansible-user: ${{ secrets.ANSIBLE_USER }} - trusted-hosts: ${{ secrets.TRUSTED_HOSTS }} - name: Apply the playbook that triggered the workflow env: diff --git a/.github/workflows/deploy-websites.yaml.disabled b/.github/workflows/deploy-websites.yaml.disabled index f529f77..87e8ddd 100644 --- a/.github/workflows/deploy-websites.yaml.disabled +++ b/.github/workflows/deploy-websites.yaml.disabled @@ -37,7 +37,6 @@ jobs: organization-id: ${{ secrets.BW_ORGANIZATION_ID }} access-token: ${{ secrets.BW_ACCESS_TOKEN }} ansible-user: ${{ secrets.ANSIBLE_USER }} - trusted-hosts: ${{ secrets.TRUSTED_HOSTS }} - name: Run hugo_build command run: bin/hugo_build