Week 48 Focus: Repository Separation & CI/CD Foundation Key Objectives: - Create separate ansible-inventories repository (PUBLIC) - Create separate secrets repository (PRIVATE) - Implement Gitea Actions CI/CD workflows - Apply Docker security hardening improvements Tasks: 1. Repository Separation (P0/P1): - ansible-inventories: Public repo with dynamic inventories - secrets: Private repo for SSH keys and vaults - Git submodule integration for both 2. CI/CD Pipeline (P1): - Gitea Actions workflows for ansible-lint - YAML validation workflow - Automated testing on push/PR 3. Docker Security (P1): - User namespace remapping implementation - Resource limits for all containers - Image version pinning audit - Comprehensive hardening guide 4. Documentation (P2): - Submodule workflow guide - CI/CD setup documentation - Docker hardening guide Following CLAUDE.md guidelines for repository structure: - inventories: Public repository - secrets: Private repository - Main repo: Public with submodules Timeline: Nov 18-24, 2025 Builds on: Week 47 git authentication and infrastructure recovery 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
20 KiB
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:
./inventoriesshall be kept in a public git repository - Need separation for security and modularity
Execution Steps:
# 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 - Main playbooks and roles
- 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
Co-Authored-By: Claude noreply@anthropic.com"
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 - Main playbooks and roles (PUBLIC)
- 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
Co-Authored-By: Claude noreply@anthropic.com"
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 <noreply@anthropic.com>"
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:
# 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:
docker info | grep "userns"
2. Resource Limits
All containers should have memory and CPU limits.
Example docker-compose.yml:
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:
image: pihole/pihole:latest
Good:
image: pihole/pihole:2023.11.0
Testing
Test user namespace remapping:
# 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
Co-Authored-By: Claude noreply@anthropic.com"
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
git clone --recurse-submodules ssh://git@git.mymx.me:2222/ansible/infra-automation.git
Updating Submodules
git submodule update --remote
Working with Submodules
# 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
-
Submodule complexity - Team may need training on submodule workflow
- Mitigation: Create comprehensive documentation and cheatsheets
-
Gitea Actions availability - May need to enable in Gitea settings
- Mitigation: Document setup process, use webhooks as fallback
-
Docker hardening breaking existing containers
- Mitigation: Test on non-production first, document rollback
Related Documents
- TODO.md - Project-wide task tracking
- IMPROVEMENT_PLAN.md - Overall improvement strategy
- TASKS_WEEK_47.md - Previous week's tasks
- 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