# Week 48 - Executable Task Plan **Week:** November 18-24, 2025 **Focus:** Repository Separation & CI/CD Foundation **Status:** 🟢 PLANNED --- ## Overview Week 48 focuses on establishing proper repository structure and beginning CI/CD pipeline implementation. This builds on Week 47's completion of git authentication and infrastructure recovery. **Goals:** - ✅ Separate inventories into dedicated repository - ✅ Separate secrets into dedicated private repository - ✅ Begin CI/CD pipeline setup (Gitea Actions) - ✅ Improve Docker container security **Dependencies Resolved:** - ✅ Git SSH authentication working (Week 47) - ✅ Gitea repository operational (Week 47) - ✅ SSH key management documented (Week 47) --- ## Week 48 Status **Progress:** Not Started **Completed Tasks:** 0/8 **Blocked Tasks:** 0 **At Risk:** 0 --- ## Daily Breakdown ### Monday, Nov 18 (Day 1) #### Task 1.1: Create Separate Inventories Repository [P1 - HIGH] **Priority:** P1 - HIGH **Estimated Time:** 2-3 hours **Status:** 🔴 NOT STARTED **Dependencies:** Git SSH authentication (✅ completed) **Objective:** Create dedicated public repository for Ansible inventories following CLAUDE.md guidelines **Issue:** - Current inventories mixed with main codebase - CLAUDE.md requires: `./inventories` shall be kept in a *public* git repository - Need separation for security and modularity **Execution Steps:** ```bash # Step 1: Create inventories repository on Gitea cat > /tmp/create_inventories_repo.sh << 'SCRIPT' #!/bin/bash GITEA_USER="ansible@mymx.me" GITEA_PASS='79,;,metOND' GITEA_URL="https://git.mymx.me" curl -s -X POST "${GITEA_URL}/api/v1/user/repos" \ -u "${GITEA_USER}:${GITEA_PASS}" \ -H "accept: application/json" \ -H "Content-Type: application/json" \ -d '{ "name": "ansible-inventories", "description": "Ansible dynamic inventories and host configurations (PUBLIC)", "private": false, "auto_init": false, "default_branch": "master", "trust_model": "default" }' SCRIPT chmod +x /tmp/create_inventories_repo.sh /tmp/create_inventories_repo.sh # Step 2: Create local inventories repository structure mkdir -p ../ansible-inventories cd ../ansible-inventories git init # Step 3: Create directory structure mkdir -p {production,staging,development}/{group_vars,host_vars} mkdir -p production/inventory_plugins mkdir -p docs # Step 4: Create README cat > README.md << 'EOF' # Ansible Inventories Dynamic inventory configurations for Ansible infrastructure automation. ## Structure ``` . ├── production/ # Production environment │ ├── libvirt.yml # Libvirt dynamic inventory │ ├── group_vars/ # Group variables │ └── host_vars/ # Host-specific variables ├── staging/ # Staging environment └── development/ # Development environment ``` ## Usage ```bash # List production inventory ansible-inventory -i production/libvirt.yml --list # Test connectivity ansible all -i production/libvirt.yml -m ping ``` ## Related Repositories - [infra-automation](https://git.mymx.me/ansible/infra-automation) - Main playbooks and roles - [secrets](https://git.mymx.me/ansible/secrets) - Private secrets repository EOF # Step 5: Copy current inventory configuration cp ../infra-automation/inventories/libvirt.yml production/ cp -r ../infra-automation/group_vars production/ 2>/dev/null || true cp -r ../infra-automation/host_vars production/ 2>/dev/null || true # Step 6: Create .gitignore cat > .gitignore << 'EOF' *.retry *.pyc __pycache__/ .vscode/ .idea/ *.swp *~ .DS_Store EOF # Step 7: Initial commit git add . git commit -m "Initial commit: Dynamic inventory structure - Production/staging/development environment structure - Libvirt dynamic inventory configuration - Group and host variables - Documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude " # Step 8: Add remote and push git remote add origin ssh://git@git.mymx.me:2222/ansible/ansible-inventories.git git push -u origin master # Step 9: Update main repository to use inventory submodule cd ../infra-automation git submodule add ssh://git@git.mymx.me:2222/ansible/ansible-inventories.git inventories git commit -m "Add inventories as git submodule" git push origin master ``` **Acceptance Criteria:** - [ ] ansible-inventories repository created on Gitea - [ ] Repository structure follows CLAUDE.md requirements - [ ] Production inventory functional - [ ] README documentation complete - [ ] Submodule linked in main repository - [ ] Can execute ansible commands using new inventory **Deliverables:** - [ ] ansible-inventories repository (public) - [ ] Production libvirt inventory functional - [ ] Submodule integration in infra-automation - [ ] Documentation: docs/inventory-structure.md **Rollback Plan:** - Repository can be deleted if issues arise - Main repository unaffected until submodule added - Can revert submodule commit if needed --- #### Task 1.2: Create Secrets Repository [P0 - CRITICAL] **Priority:** P0 - CRITICAL **Estimated Time:** 1-2 hours **Status:** 🔴 NOT STARTED **Dependencies:** Git SSH authentication (✅ completed) **Objective:** Create dedicated PRIVATE repository for secrets following CLAUDE.md guidelines **Issue:** - secrets/ directory currently in main repository - CLAUDE.md requires: `./secrets` shall be kept in a *private* git repository - Security risk having secrets in public/main repo **Execution Steps:** ```bash # Step 1: Create private secrets repository on Gitea cat > /tmp/create_secrets_repo.sh << 'SCRIPT' #!/bin/bash GITEA_USER="ansible@mymx.me" GITEA_PASS='79,;,metOND' GITEA_URL="https://git.mymx.me" curl -s -X POST "${GITEA_URL}/api/v1/user/repos" \ -u "${GITEA_USER}:${GITEA_PASS}" \ -H "accept: application/json" \ -H "Content-Type: application/json" \ -d '{ "name": "secrets", "description": "Ansible secrets and vault files (PRIVATE - DO NOT MAKE PUBLIC)", "private": true, "auto_init": false, "default_branch": "master", "trust_model": "default" }' SCRIPT chmod +x /tmp/create_secrets_repo.sh /tmp/create_secrets_repo.sh # Step 2: Initialize secrets as separate git repository cd secrets git init # Step 3: Create README with security warnings cat > README.md << 'EOF' # Ansible Secrets Repository ⚠️ **PRIVATE REPOSITORY - CONTAINS SENSITIVE DATA** This repository contains Ansible Vault files, SSH keys, and other secrets. ## ⚠️ Security Guidelines - **NEVER** make this repository public - **NEVER** commit unencrypted secrets - **ALWAYS** use Ansible Vault for sensitive data - **ROTATE** SSH keys and passwords regularly - **REVIEW** access logs periodically ## Structure ``` . ├── ssh/ # SSH keys │ ├── ansible # Main automation key │ ├── ansible.pub │ └── README.md # Key documentation with passphrases ├── machines/ # Machine-specific secrets └── vaults/ # Ansible vault files ├── production.yml └── staging.yml ``` ## Usage ```bash # View vault contents ansible-vault view vaults/production.yml # Edit vault ansible-vault edit vaults/production.yml # Encrypt new file ansible-vault encrypt newfile.yml ``` ## Related Repositories - [infra-automation](https://git.mymx.me/ansible/infra-automation) - Main playbooks and roles (PUBLIC) - [ansible-inventories](https://git.mymx.me/ansible/ansible-inventories) - Inventories (PUBLIC) EOF # Step 4: Create .gitignore to prevent accidental commits cat > .gitignore << 'EOF' # Prevent committing unencrypted sensitive files *.pem *.key !*.pub *_rsa *_dsa *_ecdsa *_ed25519 !*_*.pub # Temporary files *.tmp *.bak *~ .DS_Store # Editor files .vscode/ .idea/ *.swp EOF # Step 5: Create vault password file placeholder (not committed) echo "# Create .vault_password file with vault password (NOT committed to git)" > .vault_password.example # Step 6: Initial commit git add README.md .gitignore .vault_password.example ssh/ git commit -m "Initial commit: Secrets repository structure - SSH keys directory with ansible automation key - Vault structure for production/staging - Security guidelines documentation - .gitignore to prevent accidental secret commits ⚠️ PRIVATE REPOSITORY - DO NOT MAKE PUBLIC 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude " # Step 7: Add remote and push git remote add origin ssh://git@git.mymx.me:2222/ansible/secrets.git git push -u origin master # Step 8: Update main repository to use secrets submodule cd .. git submodule add ssh://git@git.mymx.me:2222/ansible/secrets.git secrets git commit -m "Add secrets as git submodule (private)" git push origin master # Step 9: Verify secrets repository is PRIVATE curl -s -X GET "https://git.mymx.me/api/v1/repos/ansible/secrets" | jq '.private' # Should return: true ``` **Acceptance Criteria:** - [ ] secrets repository created and marked PRIVATE - [ ] Verified repository is not publicly accessible - [ ] SSH keys preserved and documented - [ ] README with security warnings present - [ ] .gitignore prevents accidental commits - [ ] Submodule linked in main repository - [ ] Can access secrets via submodule **Deliverables:** - [ ] secrets repository (PRIVATE on Gitea) - [ ] Verified private access controls - [ ] Submodule integration in infra-automation - [ ] Security documentation **Rollback Plan:** - Can delete repository if setup fails - SSH keys backed up before migration - Main repository unaffected until submodule added **Security Notes:** - ⚠️ Verify repository is PRIVATE before pushing - ⚠️ Never commit unencrypted secrets - ⚠️ Test access controls after creation - ⚠️ Document who has access to repository --- ### Tuesday, Nov 19 (Day 2) #### Task 2.1: Setup Gitea Actions Workflow [P1 - HIGH] **Priority:** P1 - HIGH **Estimated Time:** 3-4 hours **Status:** 🔴 NOT STARTED **Dependencies:** Repository structure (Task 1.1, 1.2) **Objective:** Implement CI/CD pipeline using Gitea Actions for automated testing **Execution Steps:** ```bash # Step 1: Create .gitea/workflows directory mkdir -p .gitea/workflows # Step 2: Create ansible-lint workflow cat > .gitea/workflows/ansible-lint.yml << 'EOF' name: Ansible Lint on: push: branches: [ master, develop ] pull_request: branches: [ master ] jobs: lint: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: submodules: false # Don't checkout secrets - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | python -m pip install --upgrade pip pip install ansible-core ansible-lint - name: Run ansible-lint run: | ansible-lint playbooks/*.yml || true ansible-lint roles/*/tasks/*.yml || true - name: Syntax check all playbooks run: | for playbook in playbooks/*.yml; do ansible-playbook --syntax-check "$playbook" || true done EOF # Step 3: Create YAML validation workflow cat > .gitea/workflows/yaml-validate.yml << 'EOF' name: YAML Validation on: push: branches: [ master, develop ] pull_request: branches: [ master ] jobs: validate: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: submodules: false - name: Install yamllint run: | pip install yamllint - name: Run yamllint run: | yamllint -c .yamllint.yml . EOF # Step 4: Create .yamllint.yml configuration cat > .yamllint.yml << 'EOF' --- extends: default rules: line-length: max: 120 level: warning comments: min-spaces-from-content: 1 indentation: spaces: 2 truthy: allowed-values: ['true', 'false', 'yes', 'no'] ignore: | .github/ .gitea/ venv/ .venv/ EOF # Step 5: Commit workflow files git add .gitea/ .yamllint.yml git commit -m "Add Gitea Actions CI/CD workflows - ansible-lint workflow for code quality - YAML validation workflow - yamllint configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude " git push origin master ``` **Acceptance Criteria:** - [ ] Gitea Actions workflows created - [ ] ansible-lint workflow functional - [ ] YAML validation workflow functional - [ ] Workflows trigger on push/PR - [ ] Can view workflow results in Gitea UI **Deliverables:** - [ ] .gitea/workflows/ansible-lint.yml - [ ] .gitea/workflows/yaml-validate.yml - [ ] .yamllint.yml configuration - [ ] Documentation: docs/ci-cd-setup.md --- #### Task 2.2: Implement Docker Security Improvements [P1 - HIGH] **Priority:** P1 - HIGH **Estimated Time:** 2-3 hours **Status:** 🔴 NOT STARTED **Dependencies:** Week 47 Docker audit completed **Objective:** Address Docker security findings from Week 47 audit **Reference:** See docs/security/docker-security-findings.md **Execution Steps:** ```bash # Step 1: Create Docker security hardening playbook cat > playbooks/harden_docker.yml << 'EOF' --- - name: Docker Security Hardening hosts: all become: true gather_facts: true vars: docker_userns_remap: "dockremap" tasks: - name: Check if Docker is installed ansible.builtin.command: docker --version register: docker_check failed_when: false changed_when: false - name: Skip if Docker not installed ansible.builtin.meta: end_host when: docker_check.rc != 0 # User namespace remapping - name: Create dockremap user ansible.builtin.user: name: "{{ docker_userns_remap }}" system: yes create_home: no - name: Configure user namespace remapping ansible.builtin.lineinfile: path: /etc/docker/daemon.json line: ' "userns-remap": "{{ docker_userns_remap }}",' insertafter: '^\{' create: yes backup: yes notify: restart docker # Resource limits - name: Add resource limits to docker-compose files ansible.builtin.blockinfile: path: "{{ item }}" marker: "# {mark} ANSIBLE MANAGED RESOURCE LIMITS" block: | deploy: resources: limits: memory: 1G cpus: '1.0' reservations: memory: 256M cpus: '0.5' loop: "{{ lookup('fileglob', '/opt/*/docker-compose.yml', wantlist=True) }}" when: lookup('fileglob', '/opt/*/docker-compose.yml', wantlist=True) | length > 0 # Pin image versions - name: Audit container image versions ansible.builtin.shell: | docker ps --format "{{.Image}}" | grep -E ":latest|^[^:]+$" register: latest_images changed_when: false failed_when: false - name: Warn about latest tags ansible.builtin.debug: msg: "WARNING: Containers using :latest or no tag: {{ latest_images.stdout_lines }}" when: latest_images.stdout_lines | length > 0 handlers: - name: restart docker ansible.builtin.systemd: name: docker state: restarted EOF # Step 2: Create documentation cat > docs/docker-hardening-guide.md << 'EOF' # Docker Security Hardening Guide ## Implemented Security Measures ### 1. User Namespace Remapping User namespace remapping isolates container processes from host processes. **Implementation:** ```bash ansible-playbook playbooks/harden_docker.yml ``` **Verification:** ```bash docker info | grep "userns" ``` ### 2. Resource Limits All containers should have memory and CPU limits. **Example docker-compose.yml:** ```yaml services: app: image: myapp:1.2.3 deploy: resources: limits: memory: 1G cpus: '1.0' reservations: memory: 256M cpus: '0.5' ``` ### 3. Image Version Pinning Never use `:latest` tags in production. **Bad:** ```yaml image: pihole/pihole:latest ``` **Good:** ```yaml image: pihole/pihole:2023.11.0 ``` ## Testing Test user namespace remapping: ```bash # Before docker run --rm busybox id # uid=0(root) gid=0(root) # After (with userns remap) docker run --rm busybox id # uid=1000(dockremap) gid=1000(dockremap) ``` ## References - Docker security best practices: https://docs.docker.com/engine/security/ - CIS Docker Benchmark - NIST Container Security Guide EOF # Step 3: Commit files git add playbooks/harden_docker.yml docs/docker-hardening-guide.md git commit -m "Add Docker security hardening - User namespace remapping playbook - Resource limits implementation - Image version pinning audit - Comprehensive hardening guide Addresses findings from Week 47 Docker audit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude " git push origin master ``` **Acceptance Criteria:** - [ ] Docker hardening playbook created - [ ] User namespace remapping functional - [ ] Resource limits documented - [ ] Image version audit implemented - [ ] Documentation complete **Deliverables:** - [ ] playbooks/harden_docker.yml - [ ] docs/docker-hardening-guide.md - [ ] Updated Docker security findings --- ### Wednesday-Friday, Nov 20-22 (Days 3-5) #### Task 3.1: Test Submodule Workflow [P2 - MEDIUM] **Priority:** P2 - MEDIUM **Estimated Time:** 1-2 hours **Status:** 🔴 NOT STARTED **Objective:** Ensure submodule workflow is functional and documented **Execution Steps:** ```bash # Test cloning with submodules cd /tmp git clone ssh://git@git.mymx.me:2222/ansible/infra-automation.git test-clone cd test-clone # Initialize submodules git submodule init git submodule update # Verify structure ls -la inventories/ secrets/ # Test updates cd inventories git pull origin master cd .. git add inventories git commit -m "Update inventories submodule" # Create documentation cat > docs/submodule-workflow.md << 'EOF' # Git Submodule Workflow ## Initial Clone ```bash git clone ssh://git@git.mymx.me:2222/ansible/infra-automation.git cd infra-automation git submodule init git submodule update ``` ## Or clone with submodules ```bash git clone --recurse-submodules ssh://git@git.mymx.me:2222/ansible/infra-automation.git ``` ## Updating Submodules ```bash git submodule update --remote ``` ## Working with Submodules ```bash # Make changes in submodule cd inventories git checkout master # Make changes git commit -am "Update inventory" git push origin master # Update parent repository cd .. git add inventories git commit -m "Update inventories submodule" git push origin master ``` ## References - Git Submodules: https://git-scm.com/book/en/v2/Git-Tools-Submodules EOF ``` **Acceptance Criteria:** - [ ] Can clone with submodules - [ ] Can update submodules - [ ] Can make changes in submodules - [ ] Documentation complete --- ### Week Review - Friday, Nov 22 #### Task 4.1: Update Documentation and Metrics [P2 - MEDIUM] **Priority:** P2 - MEDIUM **Estimated Time:** 1-2 hours **Status:** 🔴 NOT STARTED **Execution Steps:** ```bash # Update TODO.md with Week 48 completion # Update SUMMARY.md with new metrics # Create TASKS_WEEK_49.md # Commit all changes ``` --- ## Success Criteria ### Must Complete (P0-P1) - [ ] Inventories repository created and functional - [ ] Secrets repository created (PRIVATE) and functional - [ ] Gitea Actions workflows operational - [ ] Docker security improvements implemented ### Should Complete (P2) - [ ] Submodule workflow tested and documented - [ ] Weekly metrics updated - [ ] Week 49 plan created --- ## Metrics Tracking | Metric | Start of Week | Target | Current | |--------|---------------|--------|---------| | Separated Repositories | 1 | 3 | ___ | | CI/CD Pipeline | 0% | 50% | ___ | | Docker Security Score | 60% | 80% | ___ | | Submodule Integration | 0% | 100% | ___ | --- ## Blockers and Risks ### Potential Risks 1. **Submodule complexity** - Team may need training on submodule workflow - Mitigation: Create comprehensive documentation and cheatsheets 2. **Gitea Actions availability** - May need to enable in Gitea settings - Mitigation: Document setup process, use webhooks as fallback 3. **Docker hardening breaking existing containers** - Mitigation: Test on non-production first, document rollback --- ## Related Documents - [TODO.md](TODO.md) - Project-wide task tracking - [IMPROVEMENT_PLAN.md](IMPROVEMENT_PLAN.md) - Overall improvement strategy - [TASKS_WEEK_47.md](TASKS_WEEK_47.md) - Previous week's tasks - [ROADMAP.md](ROADMAP.md) - Long-term strategic plan --- **Week Start:** 2025-11-18 (Monday) **Week End:** 2025-11-24 (Sunday) **Review Date:** 2025-11-22 (Friday) **Next Planning:** 2025-11-25 (Monday) - Week 49