--- - name: Create and Configure New LXC Container hosts: localhost gather_facts: no vars_files: - "../secrets.yml" - "../vars.yml" vars_prompt: - name: container_name prompt: "Enter the new container name" private: no - name: container_ip prompt: "Enter the IP address" private: no - name: container_id prompt: "Enter the Container ID (VMID)" private: no - name: container_cores prompt: "Enter CPU Cores" default: "2" private: no - name: container_memory prompt: "Enter Memory in MB" default: "256" private: no tasks: - name: Normalize IP address (append /24 if missing) set_fact: container_ip_cidr: "{{ container_ip if '/' in container_ip else container_ip + '/24' }}" - name: Create LXC container on Proxmox community.general.proxmox: api_host: "{{ proxmox_host | default('10.0.0.1') }}" api_user: "{{ proxmox_api_user }}" api_token_id: "{{ proxmox_api_token_id }}" api_token_secret: "{{ proxmox_api_token_secret }}" node: "{{ proxmox_node }}" storage: "{{ proxmox_storage }}" ostemplate: '{{ proxmox_storage }}:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst' vmid: "{{ container_id }}" hostname: "{{ container_name }}" password: "{{ ansible_password }}" pubkey: "{{ my_public_keys | join('\n') }}" netif: net0: "name=eth0,gw=10.0.0.1,ip={{ container_ip_cidr }},bridge=vmbr0" cores: "{{ container_cores }}" memory: "{{ container_memory }}" swap: 512 state: present unprivileged: yes features: - nesting=1 register: proxmox_creation - name: Start the container community.general.proxmox: api_host: "{{ proxmox_host | default('10.0.0.1') }}" api_user: "{{ proxmox_api_user }}" api_token_id: "{{ proxmox_api_token_id }}" api_token_secret: "{{ proxmox_api_token_secret }}" vmid: "{{ container_id }}" state: started - name: Wait for container to be reachable wait_for: host: "{{ container_ip_cidr | split('/') | first }}" port: 22 search_regex: OpenSSH delay: 10 timeout: 300 - name: Add new host to in-memory inventory (group 'new') add_host: name: "{{ container_name }}" groups: new ansible_host: "{{ container_ip_cidr | split('/') | first }}" ansible_user: root ansible_user: root # Removed ansible_ssh_pass - we rely on the injected key ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' - name: Secure and Configure New Container hosts: new gather_facts: no vars: # We must explicitly use the password here because the 'new' group in inventory might not have it set # We use the key for the initial root connection, NOT the password # Set ansible_ssh_private_key_file if needed, otherwise it uses the agent ansible_user: root ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' vars_files: - "../vars.yml" tasks: # Updated to verify SSH key works, not password - name: Verify we can connect (ping) ping: - name: Create user '{{ target_user }}' ansible.builtin.user: name: '{{ target_user }}' shell: /bin/bash groups: sudo state: present - name: Allow '{{ target_user }}' to use sudo without a password ansible.builtin.copy: dest: /etc/sudoers.d/90-{{ target_user }}-nopasswd content: '{{ target_user }} ALL=(ALL) NOPASSWD: ALL' mode: '0440' validate: /usr/sbin/visudo -cf %s - name: Set up authorized_keys for '{{ target_user }}' ansible.posix.authorized_key: user: '{{ target_user }}' key: "{{ item }}" state: present path: /home/{{ target_user }}/.ssh/authorized_keys loop: "{{ my_public_keys }}" - name: Lock password for '{{ target_user }}' ansible.builtin.user: name: '{{ target_user }}' password_lock: yes - name: Disallow root login over SSH ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^#?PermitRootLogin' line: 'PermitRootLogin no' validate: /usr/sbin/sshd -t -f %s notify: restart sshd - name: Disallow password authentication ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^#?PasswordAuthentication' line: 'PasswordAuthentication no' validate: /usr/sbin/sshd -t -f %s notify: restart sshd handlers: - name: restart sshd ansible.builtin.service: name: sshd state: restarted - name: Persist Host to Inventory hosts: localhost gather_facts: no tasks: - name: Add new host to local hosts.ini file ansible.builtin.blockinfile: path: "{{ playbook_dir }}/../inventory/hosts.ini" block: | {{ hostvars[item]['inventory_hostname'] }} ansible_host={{ hostvars[item]['ansible_host'] }} insertafter: "^\\[lxc\\]" marker: "# {mark} ANSIBLE MANAGED BLOCK FOR HOST {{ hostvars[item]['inventory_hostname'] }}" loop: "{{ groups['new'] }}"