proxmox ci api user
This commit is contained in:
parent
bdf3bc6b02
commit
c05c863fda
8 changed files with 147 additions and 52 deletions
|
|
@ -35,7 +35,7 @@ This repository contains Ansible playbooks and roles for bootstrapping a fresh P
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# group_vars/all/vault.yml
|
# group_vars/all/vault.yml
|
||||||
initial_root_password: "YourActualProxmoxRootPassword"
|
vault_proxmox_initial_root_password: "YourActualProxmoxRootPassword"
|
||||||
```
|
```
|
||||||
Save and exit.
|
Save and exit.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,43 @@ proxmox_network_cidr: "24"
|
||||||
proxmox_network_gateway: "192.168.1.1"
|
proxmox_network_gateway: "192.168.1.1"
|
||||||
proxmox_physical_nic: "eno1" # Main NIC for vmbr0
|
proxmox_physical_nic: "eno1" # Main NIC for vmbr0
|
||||||
|
|
||||||
# General system-wide variables
|
# Proxmox API
|
||||||
admin:
|
# proxmox_role_id: CI_VM_Admin
|
||||||
name: "plasmagoat"
|
# proxmox_role_privs: "VM.Allocate,VM.Audit,VM.Clone,VM.PowerMgmt,Datastore.Allocate,Datastore.Audit,Datastore.Read,Datastore.Backup,Sys.Audit"
|
||||||
groups: ["sudo"]
|
proxmox_api_user_name: ci-user # Name for the Proxmox API user
|
||||||
shell: /bin/bash
|
proxmox_api_user_realm: pam # Realm for the Proxmox API user (e.g., 'pam', 'pve')
|
||||||
ssh_keys:
|
proxmox_api_user_role: PVEAdmin
|
||||||
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICUP7m8jZJiclZGfSje8CeBYFhX10SrdtjYziuChmj1X plasmagoat@macbook-air"
|
proxmox_api_user_password: "{{ vault_proxmox_api_user_password }}" # Securely retrieve password
|
||||||
|
proxmox_api_token_id: ci-token # e.g., 'ci-token'
|
||||||
|
proxmox_api_token_comment: "Token for CI/CD operations on Proxmox"
|
||||||
|
proxmox_api_token_privs: # Privileges for the API Token (often defined by assigned roles)
|
||||||
|
# For a token, you typically rely on the user's roles. But you can also explicitly grant
|
||||||
|
# or restrict privileges directly on the token. Here, we'll rely on the user's role.
|
||||||
|
# You can override here if needed, e.g., ['VM.PowerMgmt', 'VM.Clone']
|
||||||
|
[]
|
||||||
|
# This should be retrieved from a secure source like Ansible Vault or environment variables.
|
||||||
|
# proxmox_api_token_secret: "{{ lookup('ansible.builtin.env', 'PROXMOX_API_TOKEN_SECRET') }}"
|
||||||
|
# OR, if using Ansible Vault:
|
||||||
|
proxmox_api_token_secret: "{{ vault_proxmox_api_token_secret }}"
|
||||||
|
|
||||||
ci_user:
|
# --- Proxmox Connection Details ---
|
||||||
name: forgejo-runner
|
proxmox_host: "192.168.1.205" # Proxmox API IP/hostname
|
||||||
groups: ["sudo"]
|
proxmox_initial_root_password: "{{ vault_proxmox_initial_root_password }}"
|
||||||
shell: /bin/bash
|
|
||||||
ssh_keys:
|
proxmox_admin_user_name: "plasmagoat"
|
||||||
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGlzZWik5bbH6/xjiCpwo1SQSJ/J/Cv7y4ZQ45P68GLB forgejo-runner"
|
proxmox_admin_user_groups: ["sudo"]
|
||||||
|
proxmox_admin_user_shell: /bin/bash
|
||||||
|
proxmox_admin_user_ssh_keys:
|
||||||
|
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICUP7m8jZJiclZGfSje8CeBYFhX10SrdtjYziuChmj1X plasmagoat@macbook-air"
|
||||||
|
|
||||||
|
proxmox_ci_user_name: ci-user
|
||||||
|
proxmox_ci_user_groups: ["sudo"]
|
||||||
|
proxmox_ci_user_shell: /bin/bash
|
||||||
|
proxmox_ci_user_ssh_key:
|
||||||
|
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGlzZWik5bbH6/xjiCpwo1SQSJ/J/Cv7y4ZQ45P68GLB forgejo-runner"
|
||||||
|
# ci_user:
|
||||||
|
# name: forgejo-runner
|
||||||
|
# groups: ["sudo"]
|
||||||
|
# shell: /bin/bash
|
||||||
|
# ssh_keys:
|
||||||
|
# - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGlzZWik5bbH6/xjiCpwo1SQSJ/J/Cv7y4ZQ45P68GLB forgejo-runner"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
61313964636437313765633263626265306663373866616265393463383838616130373639373037
|
35353166376230643231373732353138333738383563366536383031656335303630623238626663
|
||||||
6261666639613636363666626635353636343439663263320a303137653761646664633463376466
|
3934363333653763353839363435393964626437616138360a643238643032613332396135313766
|
||||||
62616630306332373862653838376563623465393130386536383666616133656538306336666165
|
38323266326262643637366364643663336166353365613139383166356233336137613961316233
|
||||||
3430373162633736610a633864623662366536353436343235353764386664376662363138376435
|
6130613761356635340a353839353434623861383363643663643930306431336134336437623663
|
||||||
66633337393735633539303565663634333635366462386465313739613762613932643231656437
|
34383235653461306631396439376462313062343031313632386339386434663365613732376431
|
||||||
3464393961663935373964623432383834643263353230313333
|
62653461356465336633613366383533356139316662653862336438356136643964653733333230
|
||||||
|
33373266656261306630636131393635656562343466303836366262646634303335613861326530
|
||||||
|
34643439653463646431373063633830323238393565306436623832633930326533626139336234
|
||||||
|
66616636333130616366366339393631316265363565623532303132373162666561396562336363
|
||||||
|
39643838653364366539386466356565366335653261396563306133323965363837326164393336
|
||||||
|
64313364393439643163633330303862373135376266643863633764343462336164303562386561
|
||||||
|
61363638313432363366636662333763313163613862326133633330383463633831613265623466
|
||||||
|
36303965353832313433383865656432633137376439336365346632313438633161
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
become: true # Use sudo for all tasks
|
become: true # Use sudo for all tasks
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
ansible_become_pass: "{{ initial_root_password }}" # Use the vaulted root password for initial connection
|
ansible_become_pass: "{{ vault_proxmox_initial_root_password }}" # Use the vaulted root password for initial connection
|
||||||
|
|
||||||
pre_tasks:
|
pre_tasks:
|
||||||
- name: Wait for SSH to be available
|
- name: Wait for SSH to be available
|
||||||
|
|
@ -20,5 +20,6 @@
|
||||||
- role: common
|
- role: common
|
||||||
- role: proxmox_setup
|
- role: proxmox_setup
|
||||||
- role: ci_user
|
- role: ci_user
|
||||||
|
- role: proxmox_api
|
||||||
# - role: cloudinit
|
# - role: cloudinit
|
||||||
# - role: networking # Uncomment if you've populated this role
|
# - role: networking # Uncomment if you've populated this role
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,34 @@
|
||||||
|
- name: Create CI group
|
||||||
|
ansible.builtin.group:
|
||||||
|
name: ci
|
||||||
|
state: present
|
||||||
|
|
||||||
- name: Create CI user
|
- name: Create CI user
|
||||||
ansible.builtin.user:
|
ansible.builtin.user:
|
||||||
name: "{{ ci_user.name }}"
|
name: "{{ proxmox_ci_user_name }}"
|
||||||
groups: "{{ ci_user.groups }}"
|
group: ci
|
||||||
shell: "{{ ci_user.shell }}"
|
groups: "{{ proxmox_ci_user_groups }}"
|
||||||
|
shell: "{{ proxmox_ci_user_shell }}"
|
||||||
state: present
|
state: present
|
||||||
create_home: yes
|
create_home: yes
|
||||||
when: ci_user.name is defined and ci_user.name | length > 0
|
when: proxmox_ci_user_name is defined and proxmox_ci_user_name | length > 0
|
||||||
|
|
||||||
- name: Add SSH keys for CI user
|
- name: Add SSH keys for CI user
|
||||||
ansible.posix.authorized_key:
|
ansible.posix.authorized_key:
|
||||||
user: "{{ ci_user.name }}"
|
user: "{{ proxmox_ci_user_name }}"
|
||||||
state: present
|
state: present
|
||||||
key: "{{ item }}"
|
key: "{{ item }}"
|
||||||
loop: "{{ ci_user.ssh_keys }}"
|
loop: "{{ proxmox_ci_user_ssh_keys }}"
|
||||||
when:
|
when:
|
||||||
- ci_user.name is defined
|
- proxmox_ci_user_name is defined
|
||||||
- ci_user.name | length > 0
|
- proxmox_ci_user_name | length > 0
|
||||||
- ci_user.ssh_keys is defined
|
- proxmox_ci_user_ssh_keys is defined
|
||||||
- ci_user.ssh_keys | length > 0
|
- proxmox_ci_user_ssh_keys | length > 0
|
||||||
|
|
||||||
|
- name: Ensure image directory exists with correct permissions
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /var/lib/vz/dump
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: ci
|
||||||
|
mode: "0775" # rwxrwxr-x so 'ci' can write, others can read/execute
|
||||||
|
|
|
||||||
|
|
@ -15,30 +15,31 @@
|
||||||
- htop
|
- htop
|
||||||
- git
|
- git
|
||||||
- rsync
|
- rsync
|
||||||
|
- jq
|
||||||
- nfs-common # If you plan to mount NFS shares
|
- nfs-common # If you plan to mount NFS shares
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Create new admin user
|
- name: Create new admin user
|
||||||
ansible.builtin.user:
|
ansible.builtin.user:
|
||||||
name: "{{ admin.name }}"
|
name: "{{ proxmox_admin_user_name }}"
|
||||||
groups: "{{ admin.groups }}"
|
groups: "{{ proxmox_admin_user_groups }}"
|
||||||
shell: "{{ admin.shell }}"
|
shell: "{{ proxmox_admin_user_shell }}"
|
||||||
state: present
|
state: present
|
||||||
create_home: yes
|
create_home: yes
|
||||||
append: yes # Ensures other groups don't get removed
|
append: yes # Ensures other groups don't get removed
|
||||||
when: admin.name is defined and admin.name | length > 0
|
when: proxmox_admin_user_name is defined and proxmox_admin_user_name | length > 0
|
||||||
|
|
||||||
- name: Add SSH keys for new admin user
|
- name: Add SSH keys for new admin user
|
||||||
ansible.posix.authorized_key:
|
ansible.posix.authorized_key:
|
||||||
user: "{{ admin.name }}"
|
user: "{{ proxmox_admin_user_name }}"
|
||||||
state: present
|
state: present
|
||||||
key: "{{ item }}"
|
key: "{{ item }}"
|
||||||
loop: "{{ admin.ssh_keys }}"
|
loop: "{{ proxmox_admin_user_ssh_keys }}"
|
||||||
when:
|
when:
|
||||||
- admin.name is defined
|
- proxmox_admin_user_name is defined
|
||||||
- admin.name | length > 0
|
- proxmox_admin_user_name | length > 0
|
||||||
- admin.ssh_keys is defined
|
- proxmox_admin_user_ssh_keys is defined
|
||||||
- admin.ssh_keys | length > 0
|
- proxmox_admin_user_ssh_keys | length > 0
|
||||||
# - name: Disable root SSH login (optional, but recommended)
|
# - name: Disable root SSH login (optional, but recommended)
|
||||||
# ansible.builtin.lineinfile:
|
# ansible.builtin.lineinfile:
|
||||||
# path: /etc/ssh/sshd_config
|
# path: /etc/ssh/sshd_config
|
||||||
|
|
|
||||||
57
roles/proxmox_api/tasks/main.yml
Normal file
57
roles/proxmox_api/tasks/main.yml
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
- name: Ensure Proxmox API user exists and has correct password (using pveum)
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -e # Exit immediately if a command exits with a non-zero status
|
||||||
|
USER_EXISTS=$(pveum user list --output-format json | jq -r '.[] | select(.userid == "{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}") | .userid')
|
||||||
|
|
||||||
|
if [ -z "$USER_EXISTS" ]; then
|
||||||
|
pveum user add "{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}" --password "{{ proxmox_api_user_password }}" --comment "CI/CD user created by Ansible" -enable 1
|
||||||
|
echo "User '{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}' was added."
|
||||||
|
else
|
||||||
|
# Always attempt to modify to ensure password/comment is up-to-date
|
||||||
|
# pveum user modify does not return 'modified' for idempotency
|
||||||
|
(echo "{{ proxmox_api_user_password }}"; echo "{{ proxmox_api_user_password }}") | pveum passwd "{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}"
|
||||||
|
pveum user modify "{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}" --comment "CI/CD user updated by Ansible"
|
||||||
|
echo "User '{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}' was modified (or already up-to-date)."
|
||||||
|
fi
|
||||||
|
register: pveum_user_result
|
||||||
|
changed_when: "'added' in pveum_user_result.stdout or 'modified' in pveum_user_result.stdout"
|
||||||
|
failed_when: pveum_user_result.rc != 0 and 'already exists' not in pveum_user_result.stderr
|
||||||
|
no_log: true # Prevent password from being logged
|
||||||
|
|
||||||
|
- name: Ensure Proxmox API token exists (using pveum)
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -e
|
||||||
|
TOKEN_INFO=$(pveum user token list "{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}" --output-format json 2>/dev/null | jq -r '.[] | select(.tokenid == "{{ proxmox_api_token_id }}")')
|
||||||
|
|
||||||
|
if [ -z "$TOKEN_INFO" ]; then
|
||||||
|
pveum user token add "{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}" "{{ proxmox_api_token_id }}" --comment "CI/CD token created by Ansible"
|
||||||
|
# echo "Token '{{ proxmox_api_token_id }}' was added. Secret: $(cat ~/.pve/token-{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}!{{ proxmox_api_token_id }}.json | jq -r '.value')" # Capture secret
|
||||||
|
else
|
||||||
|
echo "Token '{{ proxmox_api_token_id }}' for user '{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}' already exists. No action taken."
|
||||||
|
fi
|
||||||
|
register: pveum_token_result
|
||||||
|
changed_when: "'was added' in pveum_token_result.stdout"
|
||||||
|
# This task is tricky for secret capture.
|
||||||
|
# `pveum user token add` prints the secret to stdout on creation AND saves it to a file.
|
||||||
|
# We try to capture it from stdout and then from the file for robustness.
|
||||||
|
# You MUST parse `pveum_token_result.stdout` to get the secret when it's new.
|
||||||
|
# In real CI/CD, generate a new token via pveum only ONCE and store the secret
|
||||||
|
# then use `proxmox_api_token_secret` in your vars.
|
||||||
|
no_log: false # Prevent password and token secret from being logged
|
||||||
|
|
||||||
|
- debug:
|
||||||
|
var: pveum_token_result.stdout
|
||||||
|
|
||||||
|
- name: Ensure ACL for root exists
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -e
|
||||||
|
ACL_EXISTS=$(pveum acl list --output-format json 2>/dev/null | jq -r '.[] | select(.path == "/" and .user == "{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}" and .roleid == "{{ proxmox_api_user_role }}") | .path')
|
||||||
|
|
||||||
|
if [ -z "$ACL_EXISTS" ]; then
|
||||||
|
pveum acl modify / -user "{{ proxmox_api_user_name }}@{{ proxmox_api_user_realm }}" -role "{{ proxmox_api_user_role }}" -propagate 1
|
||||||
|
echo "ACL for / was added."
|
||||||
|
else
|
||||||
|
echo "ACL for / already exists."
|
||||||
|
fi
|
||||||
|
register: pveum_acl_root_result
|
||||||
|
changed_when: "'was added' in pveum_acl_root_result.stdout"
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
- name: Create CI user
|
|
||||||
ansible.builtin.user:
|
|
||||||
name: "{{ ci_user }}"
|
|
||||||
shell: /bin/bash
|
|
||||||
groups: sudo
|
|
||||||
password: "{{ ci_password | password_hash('sha512') }}"
|
|
||||||
|
|
||||||
- name: Add authorized key
|
|
||||||
ansible.posix.authorized_key:
|
|
||||||
user: "{{ ci_user }}"
|
|
||||||
key: "{{ lookup('file', '../files/ci_user.pub') }}"
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue