initial comit with first sprint of terraform and ansible files
This commit is contained in:
commit
6c9f41c26c
|
|
@ -0,0 +1,36 @@
|
|||
# EditorConfig for OpenCMMC Stack
|
||||
root = true
|
||||
|
||||
# Default settings for all files
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Python files
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
|
||||
# YAML / Ansible / Terraform files
|
||||
[*.yml]
|
||||
indent_size = 2
|
||||
[*.yaml]
|
||||
indent_size = 2
|
||||
[*.tf]
|
||||
indent_size = 2
|
||||
|
||||
# Markdown files
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
indent_size = 2
|
||||
|
||||
# Shell scripts
|
||||
[*.sh]
|
||||
indent_size = 2
|
||||
|
||||
# Mermaid diagrams
|
||||
[*.mmd]
|
||||
indent_size = 2
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# Normalize all text files to LF endings
|
||||
* text=auto eol=lf
|
||||
|
||||
# Markdown, YAML, Terraform, and code files treated as text
|
||||
*.md text
|
||||
*.markdown text
|
||||
*.yml text
|
||||
*.yaml text
|
||||
*.tf text
|
||||
*.tfvars text
|
||||
*.sh text
|
||||
*.py text
|
||||
*.mmd text
|
||||
|
||||
# Treat images and binary files as binary (no diff)
|
||||
*.svg binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.pdf binary
|
||||
*.zip binary
|
||||
*.tar.gz binary
|
||||
*.gz binary
|
||||
|
||||
# GitHub language statistics override (if needed)
|
||||
docs/** linguist-documentation
|
||||
*.md linguist-language=Markdown
|
||||
*.mmd linguist-language=Mermaid
|
||||
|
||||
# Avoid diffs on lock and compiled files
|
||||
*.lock binary
|
||||
*.retry binary
|
||||
|
|
@ -0,0 +1,301 @@
|
|||
# Local .terraform directories
|
||||
**/.terraform/*
|
||||
|
||||
# .tfstate files
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
|
||||
# Crash log files
|
||||
crash.log
|
||||
crash.*.log
|
||||
|
||||
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
|
||||
# password, private keys, and other secrets. These should not be part of version
|
||||
# control as they are data points which are potentially sensitive and subject
|
||||
# to change depending on the environment.
|
||||
*.tfvars
|
||||
*.tfvars.json
|
||||
|
||||
# Ignore override files as they are usually used to override resources locally and so
|
||||
# are not checked in
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
|
||||
# Ignore transient lock info files created by terraform apply
|
||||
.terraform.tfstate.lock.info
|
||||
|
||||
# Include override files you do wish to add to version control using negated pattern
|
||||
# !example_override.tf
|
||||
|
||||
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
|
||||
# example: *tfplan*
|
||||
|
||||
# Ignore CLI configuration files
|
||||
.terraformrc
|
||||
terraform.rc
|
||||
|
||||
*.retry
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
# ————————————————————————
|
||||
# MkDocs/Mermaid CLI Additions
|
||||
# ————————————————————————
|
||||
|
||||
# Mermaid CLI output (SVGs or temp)
|
||||
*.svg
|
||||
*.mmdc-log
|
||||
|
||||
# Mermaid cache (if any future builds generate it)
|
||||
.mermaid-cache/
|
||||
|
||||
# ————————————————————————
|
||||
# Ansible Molecule Testing
|
||||
# ————————————————————————
|
||||
|
||||
molecule/
|
||||
**/molecule/*/.tox/
|
||||
**/molecule/*/.molecule/
|
||||
**/molecule/*/logs/
|
||||
**/molecule/*/default/
|
||||
|
||||
# Lint and report files
|
||||
*.retry
|
||||
ansible-lint.log
|
||||
molecule-report.xml
|
||||
|
||||
# ————————————————————————
|
||||
# Ansible Role Packaging
|
||||
# ————————————————————————
|
||||
|
||||
*.tar.gz
|
||||
*.tar
|
||||
*.zip
|
||||
*.gz
|
||||
|
||||
# Built or temp roles
|
||||
roles/**/collections/
|
||||
roles/**/.python-version
|
||||
roles/**/__pycache__/
|
||||
roles/**/.pytest_cache/
|
||||
|
||||
# ————————————————————————
|
||||
# SSH/Secrets Safety (add for clarity)
|
||||
# ————————————————————————
|
||||
|
||||
# Never commit real keypairs or their fingerprints
|
||||
id_rsa
|
||||
id_rsa.pub
|
||||
*.pem
|
||||
*.crt
|
||||
*.key
|
||||
*.jks
|
||||
|
||||
# Example fallback (should be updated before use)
|
||||
!example_id_rsa.pub
|
||||
|
||||
# ————————————————————————
|
||||
# Terraform Local Logs and CLI Plan Files
|
||||
# ————————————————————————
|
||||
|
||||
*.log
|
||||
*.tfplan
|
||||
|
||||
# Explicitly ignore Terraform's crash diagnostic dirs
|
||||
.terraform.d/
|
||||
|
||||
# ————————————————————————
|
||||
# General Safety
|
||||
# ————————————————————————
|
||||
|
||||
# Lock files generated by CI/test runs
|
||||
.lockfile
|
||||
open-cmmc.lock
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
# 🔐 Global Access & Identity Settings
|
||||
default_user: cmmcadmin
|
||||
default_shell: /bin/bash
|
||||
ssh_authorized_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
|
||||
|
||||
# 🌐 Network & Proxy Settings
|
||||
nextcloud_port: 8080
|
||||
mailcow_port: 443
|
||||
keycloak_port: 8081
|
||||
tailscale_auth_key: tskey-abc123
|
||||
stepca_port: 9000
|
||||
wazuh_port: 55000
|
||||
|
||||
# 📦 Container Images
|
||||
nextcloud_aio_image: nextcloud/all-in-one:latest
|
||||
keycloak_image: quay.io/keycloak/keycloak:24.0.2
|
||||
|
||||
# 🗂️ Data Directories
|
||||
nextcloud_data_dir: /srv/nextcloud
|
||||
backup_base_dir: /srv/backups
|
||||
logs_dir: /var/log/open-cmmc
|
||||
|
||||
# ⚙️ System Users
|
||||
svc_keycloak: svc_keycloak
|
||||
svc_mailcow: svc_mailcow
|
||||
svc_wazuh: svc_wazuh
|
||||
svc_stepca: svc_stepca
|
||||
|
||||
# 🔄 Backup/Restore
|
||||
restic_password: changeme-securely
|
||||
restic_repo: /srv/backups/restic-repo
|
||||
|
||||
# 📛 DNS & Hostname
|
||||
domain_name: example.cmmc.local
|
||||
hostname: open-cmmc-gateway
|
||||
|
||||
# 📜 Default Realm for Keycloak
|
||||
keycloak_realm: OpenCMMC
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# file_storage Role
|
||||
|
||||
This Ansible role deploys **Nextcloud All-in-One (AIO)** as the secure file sharing and collaboration solution in the OpenCMMC Stack.
|
||||
|
||||
## Features
|
||||
|
||||
- Pulls and runs the official `nextcloud/all-in-one` container image
|
||||
- Sets up a persistent storage directory for CUI/FCI content
|
||||
- Configures container restart and port mapping for access via reverse proxy
|
||||
|
||||
## Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|-----------------------|--------------------------------------------|-----------------------------|
|
||||
| `nextcloud_aio_image` | Container image for Nextcloud AIO | `nextcloud/all-in-one:latest` |
|
||||
| `nextcloud_data_dir` | Host volume path for Nextcloud data | `/mnt/ncdata` |
|
||||
| `nextcloud_port` | Port exposed on the host | `8080` |
|
||||
|
||||
## Example Playbook
|
||||
|
||||
```yaml
|
||||
- hosts: all
|
||||
roles:
|
||||
- role: file_storage
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Make sure this container is **behind a reverse proxy** (e.g., NGINX or Caddy).
|
||||
- Configure DNS and TLS externally as needed.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
nextcloud_aio_image: "nextcloud/all-in-one:latest"
|
||||
nextcloud_container_name: "nextcloud-aio-mastercontainer"
|
||||
nextcloud_data_dir: "/opt/nextcloud/data"
|
||||
nextcloud_port: 8080
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
# Placeholder for handlers (e.g., restart Nextcloud container)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
galaxy_info:
|
||||
role_name: file_storage
|
||||
author: open-cmmc
|
||||
description: Deploy secure file collaboration using Nextcloud AIO
|
||||
license: MIT
|
||||
min_ansible_version: "2.10"
|
||||
|
||||
dependencies: []
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
- name: Create Nextcloud data directory
|
||||
file:
|
||||
path: "{{ nextcloud_data_dir }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Pull Nextcloud AIO container image
|
||||
containers.podman.podman_image:
|
||||
name: "{{ nextcloud_aio_image }}"
|
||||
|
||||
- name: Deploy Nextcloud AIO container
|
||||
containers.podman.podman_container:
|
||||
name: "{{ nextcloud_container_name }}"
|
||||
image: "{{ nextcloud_aio_image }}"
|
||||
state: started
|
||||
restart_policy: always
|
||||
ports:
|
||||
- "{{ nextcloud_port }}:8080"
|
||||
volumes:
|
||||
- "{{ nextcloud_data_dir }}:/mnt/ncdata:z"
|
||||
- "nextcloud_aio_mastercontainer:/mnt/docker-aio-config:z"
|
||||
env:
|
||||
NEXTCLOUD_DATADIR: "/mnt/ncdata"
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Identity Role
|
||||
|
||||
This role installs and configures Keycloak for identity and access management, and Step-CA for internal certificate authority needs in the OpenCMMC Stack.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
keycloak_version: "24.0.2"
|
||||
keycloak_admin_user: "admin"
|
||||
keycloak_admin_password: "securepassword"
|
||||
keycloak_realm: "OpenCMMC"
|
||||
step_ca_provisioner: "admin@example.com"
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
- name: Restart keycloak
|
||||
ansible.builtin.systemd:
|
||||
name: keycloak
|
||||
state: restarted
|
||||
enabled: true
|
||||
|
||||
- name: Restart step-ca
|
||||
ansible.builtin.systemd:
|
||||
name: step-ca
|
||||
state: restarted
|
||||
enabled: true
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
galaxy_info:
|
||||
author: OpenCMMC Team
|
||||
description: Identity and Access Management (IAM) role with Keycloak and Step-CA.
|
||||
company: Kell Engineering
|
||||
license: MIT
|
||||
min_ansible_version: "2.12"
|
||||
platforms:
|
||||
- name: Ubuntu
|
||||
versions:
|
||||
- 22.04
|
||||
dependencies: []
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
- name: Ensure Keycloak CLI (kcadm.sh) is installed
|
||||
stat:
|
||||
path: /opt/keycloak/bin/kcadm.sh
|
||||
register: kcadm_path
|
||||
|
||||
- name: Install Keycloak CLI if missing
|
||||
get_url:
|
||||
url: https://downloads.jboss.org/keycloak/24.0.2/keycloak-24.0.2.zip
|
||||
dest: /tmp/keycloak.zip
|
||||
when: not kcadm_path.stat.exists
|
||||
|
||||
- name: Unarchive Keycloak CLI
|
||||
unarchive:
|
||||
src: /tmp/keycloak.zip
|
||||
dest: /opt/
|
||||
remote_src: yes
|
||||
when: not kcadm_path.stat.exists
|
||||
|
||||
- name: Authenticate Keycloak admin CLI session
|
||||
command: >
|
||||
/opt/keycloak/bin/kcadm.sh config credentials --server http://localhost:8080/auth
|
||||
--realm master --user {{ keycloak_admin_user }} --password {{ keycloak_admin_password }}
|
||||
environment:
|
||||
KCADM_CONFIG: /opt/keycloak/kcadm.config
|
||||
|
||||
- name: Create OpenCMMC realm
|
||||
command: /opt/keycloak/bin/kcadm.sh create realms -s realm=OpenCMMC -s enabled=true
|
||||
|
||||
- name: Create groups
|
||||
loop:
|
||||
- Access_CUI
|
||||
- Access_FCI
|
||||
- Access_Proprietary
|
||||
command: /opt/keycloak/bin/kcadm.sh create groups -r OpenCMMC -s name="{{ item }}"
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
- name: Configure Keycloak realm and groups
|
||||
ansible.builtin.command:
|
||||
cmd: "/opt/keycloak/bin/kcadm.sh create realms -s realm={{ keycloak_realm }} -s enabled=true"
|
||||
when: keycloak_realm is defined
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
- name: Pull Keycloak image
|
||||
containers.podman.podman_image:
|
||||
name: quay.io/keycloak/keycloak:24.0.2
|
||||
|
||||
- name: Create systemd service user
|
||||
user:
|
||||
name: svc_keycloak
|
||||
shell: /usr/sbin/nologin
|
||||
system: yes
|
||||
create_home: no
|
||||
|
||||
- name: Create Keycloak config directory
|
||||
file:
|
||||
path: /opt/services/keycloak
|
||||
state: directory
|
||||
owner: svc_keycloak
|
||||
group: svc_keycloak
|
||||
mode: '0755'
|
||||
|
||||
- name: Deploy Keycloak container
|
||||
containers.podman.podman_container:
|
||||
name: keycloak
|
||||
image: quay.io/keycloak/keycloak:24.0.2
|
||||
state: started
|
||||
restart_policy: always
|
||||
user: svc_keycloak
|
||||
env:
|
||||
KEYCLOAK_ADMIN: "{{ keycloak_admin_user }}"
|
||||
KEYCLOAK_ADMIN_PASSWORD: "{{ keycloak_admin_password }}"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
command: "start --optimized"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
- name: Enroll clients in Step-CA
|
||||
ansible.builtin.debug:
|
||||
msg: "Provision client certificates using Step-CA"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
- name: Generate CA certs using step-ca CLI
|
||||
ansible.builtin.debug:
|
||||
msg: "Running step ca init with preconfigured values"
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
- name: Install Keycloak container
|
||||
containers.podman.podman_container:
|
||||
name: keycloak
|
||||
image: quay.io/keycloak/keycloak:{{ keycloak_version }}
|
||||
state: started
|
||||
restart_policy: always
|
||||
env:
|
||||
KEYCLOAK_ADMIN: "{{ keycloak_admin_user }}"
|
||||
KEYCLOAK_ADMIN_PASSWORD: "{{ keycloak_admin_password }}"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
- name: Setup OIDC clients for SSO integration
|
||||
ansible.builtin.debug:
|
||||
msg: "Configure OIDC clients for Mailcow, Gitea and SAML for Nextcloud"
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
- name: Include tasks to install and configure Keycloak
|
||||
include_tasks: install_keycloak.yml
|
||||
|
||||
- name: Include tasks to configure realm and users
|
||||
include_tasks: configure_realm.yml
|
||||
|
||||
- name: Include tasks to setup SSO integration
|
||||
include_tasks: integrate_sso.yml
|
||||
|
||||
- name: Include tasks to configure MFA policies
|
||||
include_tasks: setup_mfa.yml
|
||||
|
||||
- name: Include tasks to provision Step-CA
|
||||
include_tasks: provision_step_ca.yml
|
||||
|
||||
- name: Include tasks to enroll clients in Step-CA
|
||||
include_tasks: enroll_clients.yml
|
||||
|
||||
- name: Include tasks to generate CA certificates
|
||||
include_tasks: generate_ca_certs.yml
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
- name: Install step-ca and create systemd service
|
||||
ansible.builtin.copy:
|
||||
src: systemd-step-ca.service.j2
|
||||
dest: /etc/systemd/system/step-ca.service
|
||||
notify: Restart step-ca
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
- name: Enable MFA for users
|
||||
ansible.builtin.debug:
|
||||
msg: "Enabling TOTP in Keycloak authentication flow"
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
- name: Install Tailscale
|
||||
shell: curl -fsSL https://tailscale.com/install.sh | sh
|
||||
args:
|
||||
creates: /usr/bin/tailscale
|
||||
|
||||
- name: Bring up Tailscale interface
|
||||
command: tailscale up --authkey {{ tailscale_authkey }}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
[Unit]
|
||||
Description=Keycloak Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/podman start -a keycloak
|
||||
ExecStop=/usr/bin/podman stop -t 10 keycloak
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"address": ":9000",
|
||||
"dnsNames": ["stepca.{{ inventory_hostname }}"],
|
||||
"root": "step-ca-root.crt",
|
||||
"crt": "step-ca-intermediate.crt",
|
||||
"key": "step-ca-key.pem"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
your-secure-password
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Step CA
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/step-ca /etc/step-ca/config/step-ca-config.json
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
realm_clients:
|
||||
- name: nextcloud
|
||||
protocol: saml
|
||||
- name: mailcow
|
||||
protocol: oidc
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Ansible Role: keycloak_init
|
||||
|
||||
This role initializes a Keycloak instance with a predefined realm, groups, and clients for the OpenCMMC Stack.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
- name: Register SAML client for Nextcloud
|
||||
shell: '/opt/keycloak/bin/kcadm.sh create clients -r OpenCMMC -s clientId=nextcloud-aio -s protocol=saml -s enabled=true'
|
||||
|
||||
- name: Register OIDC client for Mailcow
|
||||
shell: '/opt/keycloak/bin/kcadm.sh create clients -r OpenCMMC -s clientId=mailcow -s protocol=openid-connect -s enabled=true'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
- name: Create Keycloak Groups
|
||||
shell: '/opt/keycloak/bin/kcadm.sh create groups -r OpenCMMC -s name=Access_CUI'
|
||||
|
||||
- name: Create FCI Group
|
||||
shell: '/opt/keycloak/bin/kcadm.sh create groups -r OpenCMMC -s name=Access_FCI'
|
||||
|
||||
- name: Create Proprietary Group
|
||||
shell: '/opt/keycloak/bin/kcadm.sh create groups -r OpenCMMC -s name=Access_Proprietary'
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
- name: Check if Keycloak is already installed
|
||||
stat:
|
||||
path: /opt/keycloak/bin/kcadm.sh
|
||||
register: keycloak_installed
|
||||
|
||||
- name: Download Keycloak if not already present
|
||||
unarchive:
|
||||
src: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_version }}/keycloak-{{ keycloak_version }}.tar.gz"
|
||||
dest: /opt/
|
||||
remote_src: yes
|
||||
when: not keycloak_installed.stat.exists
|
||||
|
||||
- name: Rename keycloak directory
|
||||
command: mv /opt/keycloak-{{ keycloak_version }} /opt/keycloak
|
||||
args:
|
||||
creates: /opt/keycloak/bin/kcadm.sh
|
||||
when: not keycloak_installed.stat.exists
|
||||
|
||||
- name: Set executable permissions on kcadm.sh
|
||||
file:
|
||||
path: /opt/keycloak/bin/kcadm.sh
|
||||
mode: '0755'
|
||||
when: not keycloak_installed.stat.exists
|
||||
|
||||
- name: Log in to Keycloak Admin CLI
|
||||
command: >
|
||||
/opt/keycloak/bin/kcadm.sh config credentials
|
||||
--server http://localhost:8080
|
||||
--realm master
|
||||
--user {{ keycloak_admin_user }}
|
||||
--password {{ keycloak_admin_password }}
|
||||
environment:
|
||||
KC_HOME: /opt/keycloak
|
||||
register: kcadm_login
|
||||
changed_when: false
|
||||
|
||||
- name: Create OpenCMMC realm
|
||||
command: >
|
||||
/opt/keycloak/bin/kcadm.sh create realms
|
||||
-s realm=OpenCMMC -s enabled=true
|
||||
environment:
|
||||
KC_HOME: /opt/keycloak
|
||||
when: kcadm_login is succeeded
|
||||
|
||||
- name: Create groups
|
||||
loop:
|
||||
- Access_CUI
|
||||
- Access_FCI
|
||||
- Access_Proprietary
|
||||
command: >
|
||||
/opt/keycloak/bin/kcadm.sh create groups -r OpenCMMC -s name={{ item }}
|
||||
environment:
|
||||
KC_HOME: /opt/keycloak
|
||||
when: kcadm_login is succeeded
|
||||
|
||||
- name: Create OIDC client for Mailcow
|
||||
command: >
|
||||
/opt/keycloak/bin/kcadm.sh create clients -r OpenCMMC
|
||||
-s clientId=mailcow
|
||||
-s enabled=true
|
||||
-s protocol=openid-connect
|
||||
-s publicClient=false
|
||||
-s 'redirectUris=["https://mail.yourdomain.com/*"]'
|
||||
environment:
|
||||
KC_HOME: /opt/keycloak
|
||||
when: kcadm_login is succeeded
|
||||
|
||||
- name: Create SAML client for Nextcloud
|
||||
command: >
|
||||
/opt/keycloak/bin/kcadm.sh create clients -r OpenCMMC
|
||||
-s clientId=nextcloud
|
||||
-s enabled=true
|
||||
-s protocol=saml
|
||||
-s 'redirectUris=["https://nextcloud.yourdomain.com/*"]'
|
||||
-s 'attributes.saml.assertion.signature=true'
|
||||
-s 'attributes.saml.force.post.binding=true'
|
||||
environment:
|
||||
KC_HOME: /opt/keycloak
|
||||
when: kcadm_login is succeeded
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
- name: Create Keycloak Realm
|
||||
shell: '/opt/keycloak/bin/kcadm.sh create realms -s realm=OpenCMMC -s enabled=true'
|
||||
args:
|
||||
creates: /opt/keycloak/data/realms/OpenCMMC
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
- name: Ensure kcadm.sh is present
|
||||
stat:
|
||||
path: /opt/keycloak/bin/kcadm.sh
|
||||
register: kcadm_path
|
||||
|
||||
- name: Install unzip (required for kcadm)
|
||||
apt:
|
||||
name: unzip
|
||||
state: present
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
wazuh_container_name: "wazuh-manager"
|
||||
wazuh_image: "wazuh/wazuh:latest"
|
||||
wazuh_config_path: "/opt/wazuh/config"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
# Reserved for any future log restart triggers or alert changes
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
galaxy_info:
|
||||
role_name: monitoring
|
||||
author: open-cmmc
|
||||
description: Centralized security logging and SIEM services using Wazuh and auditd
|
||||
license: MIT
|
||||
min_ansible_version: "2.10"
|
||||
|
||||
dependencies: []
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
- name: Pull Wazuh container image
|
||||
containers.podman.podman_image:
|
||||
name: wazuh/wazuh:latest
|
||||
|
||||
- name: Create Wazuh configuration directory
|
||||
file:
|
||||
path: "/opt/wazuh/config"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Deploy Wazuh container
|
||||
containers.podman.podman_container:
|
||||
name: wazuh-manager
|
||||
image: wazuh/wazuh:latest
|
||||
state: started
|
||||
restart_policy: always
|
||||
ports:
|
||||
- "1514:1514/udp"
|
||||
- "1515:1515"
|
||||
- "55000:55000"
|
||||
volumes:
|
||||
- "/opt/wazuh/config:/var/ossec/config:z"
|
||||
|
||||
- name: Ensure auditd is installed
|
||||
apt:
|
||||
name: auditd
|
||||
state: present
|
||||
update_cache: true
|
||||
become: true
|
||||
|
||||
- name: Ensure auditd service is enabled and started
|
||||
service:
|
||||
name: auditd
|
||||
state: started
|
||||
enabled: true
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Podman Services Role
|
||||
|
||||
This Ansible role provisions and manages containerized infrastructure components (excluding Nextcloud AIO) using **Podman**. It includes configurations for Wazuh, Mailcow, Redis, and more.
|
||||
|
||||
## Variables
|
||||
|
||||
```yaml
|
||||
podman_services:
|
||||
- name: redis
|
||||
image: redis:7
|
||||
state: started
|
||||
restart_policy: always
|
||||
ports: []
|
||||
volumes: []
|
||||
env: {}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Include in your playbook:
|
||||
|
||||
```yaml
|
||||
- hosts: all
|
||||
roles:
|
||||
- role: podman_services
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Only non-root Podman containers are supported
|
||||
- Customize via `podman_services` variable in `defaults/main.yml`
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
podman_services: []
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
# Reserved for future restarts
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
galaxy_info:
|
||||
role_name: podman_services
|
||||
author: open-cmmc
|
||||
description: Modular deployment of rootless Podman containers
|
||||
license: MIT
|
||||
min_ansible_version: "2.10"
|
||||
|
||||
dependencies: []
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
- name: Deploy keycloak container with Podman
|
||||
containers.podman.podman_container:
|
||||
name: keycloak
|
||||
image: "{{ keycloak_image }}"
|
||||
state: started
|
||||
restart_policy: always
|
||||
volumes:
|
||||
- "{{ keycloak_data_dir }}:/data:z"
|
||||
env:
|
||||
CONFIG_PATH: "/data/config"
|
||||
|
||||
- name: Ensure systemd service is enabled for keycloak
|
||||
copy:
|
||||
dest: "/etc/systemd/system/podman-keycloak.service"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Podman container for keycloak
|
||||
Wants=network.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/podman start -a keycloak
|
||||
ExecStop=/usr/bin/podman stop -t 10 keycloak
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Reload systemd and enable service for keycloak
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
name: podman-keycloak.service
|
||||
enabled: yes
|
||||
state: started
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
- name: Deploy mailcow container with Podman
|
||||
containers.podman.podman_container:
|
||||
name: mailcow
|
||||
image: "{{ mailcow_image }}"
|
||||
state: started
|
||||
restart_policy: always
|
||||
volumes:
|
||||
- "{{ mailcow_data_dir }}:/data:z"
|
||||
env:
|
||||
CONFIG_PATH: "/data/config"
|
||||
|
||||
- name: Ensure systemd service is enabled for mailcow
|
||||
copy:
|
||||
dest: "/etc/systemd/system/podman-mailcow.service"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Podman container for mailcow
|
||||
Wants=network.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/podman start -a mailcow
|
||||
ExecStop=/usr/bin/podman stop -t 10 mailcow
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Reload systemd and enable service for mailcow
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
name: podman-mailcow.service
|
||||
enabled: yes
|
||||
state: started
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
- name: Ensure Podman is installed
|
||||
apt:
|
||||
name: podman
|
||||
state: present
|
||||
become: true
|
||||
|
||||
- name: Pull and run Podman services
|
||||
include_tasks: run_service.yml
|
||||
loop: "{{ podman_services }}"
|
||||
loop_control:
|
||||
loop_var: service
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
- name: Pull image for {{ service.name }}
|
||||
containers.podman.podman_image:
|
||||
name: "{{ service.image }}"
|
||||
|
||||
- name: Create data directory for {{ service.name }}
|
||||
file:
|
||||
path: "{{ service.data_dir }}"
|
||||
state: directory
|
||||
owner: "{{ service.user | default('root') }}"
|
||||
group: "{{ service.group | default('root') }}"
|
||||
mode: "0755"
|
||||
|
||||
- name: Run {{ service.name }} container
|
||||
containers.podman.podman_container:
|
||||
name: "{{ service.name }}"
|
||||
image: "{{ service.image }}"
|
||||
state: started
|
||||
restart_policy: always
|
||||
ports: "{{ service.ports | default(omit) }}"
|
||||
env: "{{ service.env | default({}) }}"
|
||||
volumes: "{{ service.volumes | default([]) }}"
|
||||
user: "{{ service.user | default(omit) }}"
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
- name: Deploy step_ca container with Podman
|
||||
containers.podman.podman_container:
|
||||
name: step_ca
|
||||
image: "{{ step_ca_image }}"
|
||||
state: started
|
||||
restart_policy: always
|
||||
volumes:
|
||||
- "{{ step_ca_data_dir }}:/data:z"
|
||||
env:
|
||||
CONFIG_PATH: "/data/config"
|
||||
|
||||
- name: Ensure systemd service is enabled for step_ca
|
||||
copy:
|
||||
dest: "/etc/systemd/system/podman-step_ca.service"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Podman container for step_ca
|
||||
Wants=network.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/podman start -a step_ca
|
||||
ExecStop=/usr/bin/podman stop -t 10 step_ca
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Reload systemd and enable service for step_ca
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
name: podman-step_ca.service
|
||||
enabled: yes
|
||||
state: started
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
- name: Deploy wazuh container with Podman
|
||||
containers.podman.podman_container:
|
||||
name: wazuh
|
||||
image: "{{ wazuh_image }}"
|
||||
state: started
|
||||
restart_policy: always
|
||||
volumes:
|
||||
- "{{ wazuh_data_dir }}:/data:z"
|
||||
env:
|
||||
CONFIG_PATH: "/data/config"
|
||||
|
||||
- name: Ensure systemd service is enabled for wazuh
|
||||
copy:
|
||||
dest: "/etc/systemd/system/podman-wazuh.service"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Podman container for wazuh
|
||||
Wants=network.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/podman start -a wazuh
|
||||
ExecStop=/usr/bin/podman stop -t 10 wazuh
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Reload systemd and enable service for wazuh
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
name: podman-wazuh.service
|
||||
enabled: yes
|
||||
state: started
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
# 🔐 Ansible Role: secure_ubuntu
|
||||
|
||||
Harden an Ubuntu 22.04 LTS host to meet **CMMC Level 2** compliance requirements using a modular, auditable Ansible role.
|
||||
|
||||
This role configures:
|
||||
- SSH and login security
|
||||
- Non-root administrative user
|
||||
- System auditing and file integrity monitoring
|
||||
- UFW firewall
|
||||
- Secure banners for compliance
|
||||
- Automatic updates and password policies
|
||||
|
||||
## ✅ CMMC Practices Addressed
|
||||
|
||||
| Domain | Practice | Description |
|
||||
|--------|---------------|---------------------------------------------------------|
|
||||
| AC | AC.1.001 | Limit system access to authorized users |
|
||||
| AC | AC.3.017 | Display system use notifications (login banner) |
|
||||
| CM | CM.2.062 | Employ security configuration baseline |
|
||||
| SI | SI.1.210 | Identify unauthorized use of systems |
|
||||
| SI | SI.3.219 | Detect and report unauthorized changes to software |
|
||||
|
||||
## 📦 Requirements
|
||||
|
||||
- Ubuntu 22.04 LTS
|
||||
- Ansible >= 2.11
|
||||
|
||||
## 🚀 Role Variables
|
||||
|
||||
```yaml
|
||||
secure_user: cmmcadmin
|
||||
ssh_pubkey_path: "~/.ssh/id_rsa.pub"
|
||||
```
|
||||
|
||||
> Set `ssh_pubkey_path` to the local path of the public key to be authorized for `secure_user`.
|
||||
|
||||
## 📁 Example Playbook
|
||||
|
||||
```yaml
|
||||
- name: Apply CMMC hardening baseline
|
||||
hosts: all
|
||||
become: yes
|
||||
roles:
|
||||
- role: secure_ubuntu
|
||||
vars:
|
||||
secure_user: cmmcadmin
|
||||
ssh_pubkey_path: "~/.ssh/id_rsa.pub"
|
||||
```
|
||||
|
||||
## 📁 File Structure
|
||||
|
||||
```
|
||||
roles/
|
||||
└── secure_ubuntu/
|
||||
├── defaults/
|
||||
│ └── main.yml
|
||||
├── meta/
|
||||
│ └── main.yml
|
||||
├── tasks/
|
||||
│ ├── main.yml
|
||||
│ ├── ssh.yml
|
||||
│ ├── user.yml
|
||||
│ ├── firewall.yml
|
||||
│ ├── audit_aide.yml
|
||||
│ ├── banner.yml
|
||||
│ ├── updates.yml
|
||||
│ └── password_policy.yml
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 🔒 License
|
||||
|
||||
MIT License
|
||||
|
||||
## 🧠 Author
|
||||
|
||||
Maintained by **Kell Engineering**
|
||||
https://github.com/mtkell/open-cmmc-stack
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
admin_user: cmmcadmin
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
- name: Restart SSH
|
||||
service:
|
||||
name: ssh
|
||||
state: restarted
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
galaxy_info:
|
||||
role_name: secure_ubuntu
|
||||
author: open-cmmc
|
||||
description: Harden Ubuntu system for CMMC Level 2
|
||||
license: MIT
|
||||
min_ansible_version: "2.10"
|
||||
|
||||
dependencies: []
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
- name: Install audit and integrity tools
|
||||
apt:
|
||||
name:
|
||||
- auditd
|
||||
- aide
|
||||
state: present
|
||||
|
||||
- name: Initialize AIDE database
|
||||
command: aideinit
|
||||
args:
|
||||
creates: /var/lib/aide/aide.db.gz
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
- name: Deploy system login banner
|
||||
template:
|
||||
src: banner.txt.j2
|
||||
dest: /etc/banner.txt
|
||||
mode: '0644'
|
||||
|
||||
- name: Apply banner for SSH
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^Banner'
|
||||
line: 'Banner /etc/banner.txt'
|
||||
notify: Restart SSH
|
||||
|
||||
- name: Apply banner for console (TTY)
|
||||
copy:
|
||||
src: /etc/banner.txt
|
||||
dest: /etc/issue
|
||||
mode: '0644'
|
||||
|
||||
- name: Apply banner for pre-login
|
||||
copy:
|
||||
src: /etc/banner.txt
|
||||
dest: /etc/issue.net
|
||||
mode: '0644'
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
- name: Install UFW firewall
|
||||
apt:
|
||||
name: ufw
|
||||
state: present
|
||||
|
||||
- name: Set UFW default deny policy
|
||||
ufw:
|
||||
state: enabled
|
||||
policy: deny
|
||||
|
||||
- name: Allow SSH through firewall
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "22"
|
||||
proto: tcp
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Include SSH hardening tasks
|
||||
import_tasks: ssh.yml
|
||||
|
||||
- name: Include firewall configuration
|
||||
import_tasks: firewall.yml
|
||||
|
||||
- name: Include audit logging setup
|
||||
import_tasks: audit.yml
|
||||
|
||||
- name: Include banner setup
|
||||
import_tasks: banners.yml
|
||||
|
||||
- name: Include automatic update configuration
|
||||
import_tasks: updates.yml
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
- name: Set password complexity
|
||||
lineinfile:
|
||||
path: /etc/security/pwquality.conf
|
||||
regexp: '^minlen'
|
||||
line: 'minlen = 14'
|
||||
|
||||
- name: Lock out after 5 failed login attempts
|
||||
lineinfile:
|
||||
path: /etc/pam.d/common-auth
|
||||
line: 'auth required pam_tally2.so deny=5 onerr=fail unlock_time=900'
|
||||
create: yes
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
- name: Disable root login over SSH
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^PermitRootLogin'
|
||||
line: 'PermitRootLogin no'
|
||||
notify: Restart SSH
|
||||
|
||||
- name: Disable password authentication
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^PasswordAuthentication'
|
||||
line: 'PasswordAuthentication no'
|
||||
notify: Restart SSH
|
||||
|
||||
- name: Ensure non-root admin user exists
|
||||
user:
|
||||
name: cmmcadmin
|
||||
shell: /bin/bash
|
||||
groups: sudo
|
||||
create_home: yes
|
||||
state: present
|
||||
|
||||
- name: Add authorized SSH key for cmmcadmin
|
||||
authorized_key:
|
||||
user: cmmcadmin
|
||||
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
- name: Install unattended-upgrades
|
||||
apt:
|
||||
name: unattended-upgrades
|
||||
state: present
|
||||
|
||||
- name: Enable automatic security updates
|
||||
copy:
|
||||
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
||||
content: |
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
- name: Ensure non-root user exists
|
||||
user:
|
||||
name: cmmcadmin
|
||||
shell: /bin/bash
|
||||
groups: sudo
|
||||
state: present
|
||||
create_home: yes
|
||||
|
||||
- name: Add authorized SSH key for cmmcadmin
|
||||
authorized_key:
|
||||
user: cmmcadmin
|
||||
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
*** WARNING ***
|
||||
|
||||
This computer system is the property of {{ organization_name | default('Your Organization') }}. It is for authorized use only.
|
||||
|
||||
By accessing this system, you acknowledge and consent to the following:
|
||||
- All information is subject to monitoring by authorized personnel.
|
||||
- Unauthorized use may result in disciplinary action, civil penalties, or criminal prosecution.
|
||||
- You agree to comply with all security and data handling policies.
|
||||
|
||||
This system is protected under CMMC Level 2 compliance controls.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
- name: Test secure_ubuntu role on localhost
|
||||
hosts: localhost
|
||||
become: yes
|
||||
gather_facts: true
|
||||
|
||||
vars:
|
||||
secure_user: testadmin
|
||||
ssh_pubkey_path: "~/.ssh/id_rsa.pub"
|
||||
ssh_port: 22
|
||||
|
||||
roles:
|
||||
- role: secure_ubuntu
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
- name: Harden Ubuntu for CMMC Stack
|
||||
hosts: localhost
|
||||
become: yes
|
||||
roles:
|
||||
- secure_ubuntu
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
- name: Apply baseline security and deploy OpenCMMC Stack
|
||||
hosts: all
|
||||
become: true
|
||||
roles:
|
||||
- role: secure_ubuntu
|
||||
- role: identity
|
||||
- role: podman_services
|
||||
- role: file_storage
|
||||
- role: monitoring
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 📌 Evidence – Scoping Documentation
|
||||
|
||||
## Purpose
|
||||
This section documents the scoping boundaries for the OpenCMMC Stack environment. It includes diagrams, system inventory, and asset classification relevant to CMMC Level 2 compliance.
|
||||
|
||||
## Included Artifacts
|
||||
- Network/system diagrams
|
||||
- Inventory list
|
||||
- Boundary identification
|
||||
- Cloud vs. on-prem segregation
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Scope document reviewed by compliance officer
|
||||
- [ ] Asset list includes all CUI-processing components
|
||||
- [ ] Diagrams show trust boundaries and segmentation
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 🔐 Evidence – Identity and Access Management
|
||||
|
||||
## Purpose
|
||||
This folder contains evidence showing how user accounts, roles, MFA, and authentication systems are managed via Keycloak and Tailscale.
|
||||
|
||||
## Included Artifacts
|
||||
- Realm export (`keycloak-realm-export.json`)
|
||||
- Screenshots of MFA policy
|
||||
- Group-to-role mapping export
|
||||
- Tailscale ACL and device log
|
||||
|
||||
## Review Checklist
|
||||
- [ ] MFA enforced for all privileged users
|
||||
- [ ] User roles mapped and validated
|
||||
- [ ] Keycloak policies match SSP configuration
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 📋 Evidence – Ansible Execution Logs
|
||||
|
||||
## Description
|
||||
This directory contains raw output of Ansible playbooks applied to the Ubuntu host.
|
||||
|
||||
## Artifacts
|
||||
- `secure_ubuntu_run.log`
|
||||
- `ansible-playbook-timestamped.json`
|
||||
- Output showing configuration and user enforcement
|
||||
|
||||
## Reviewer Notes
|
||||
Ensure playbook includes:
|
||||
- SSH key enforcement
|
||||
- Root login disabled
|
||||
- Required auditd and aide tasks completed
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 🛡️ Evidence – System Hardening
|
||||
|
||||
## Purpose
|
||||
Evidence of host OS and container baseline security including hardened configurations, SSH controls, and auditd/aide logs.
|
||||
|
||||
## Included Artifacts
|
||||
- Ansible playbook logs
|
||||
- Auditd rules and logs
|
||||
- SSH daemon configs
|
||||
- AIDE database init and scan result
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Ansible logs show successful hardening
|
||||
- [ ] Login banners and password policies verified
|
||||
- [ ] Audit and integrity scans scheduled
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 📁 Evidence – File Sharing & Collaboration
|
||||
|
||||
## Purpose
|
||||
Evidence of Nextcloud AIO configuration for secure file sharing and internal team access controls.
|
||||
|
||||
## Included Artifacts
|
||||
- SAML config screenshots
|
||||
- File Access Control rules
|
||||
- Team Folder setup for CUI/FCI
|
||||
- Antivirus scanner logs
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Access control groups defined
|
||||
- [ ] External sharing is blocked for CUI
|
||||
- [ ] Antivirus scans for uploads are active
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# ✉️ Evidence – Secure Email Configuration
|
||||
|
||||
## Purpose
|
||||
Evidence related to the secure deployment and configuration of Mailcow for sending and receiving secure communications.
|
||||
|
||||
## Included Artifacts
|
||||
- TLS/DKIM/SPF reports
|
||||
- SSO integration with Keycloak
|
||||
- Mail logs for delivery success and rejection
|
||||
- Email relay and filter rules
|
||||
|
||||
## Review Checklist
|
||||
- [ ] DKIM keys configured and tested
|
||||
- [ ] TLS enforced on all SMTP/IMAP traffic
|
||||
- [ ] Mailcow access restricted via Tailscale ACLs
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 📡 Evidence – Monitoring & SIEM Integration
|
||||
|
||||
## Purpose
|
||||
Evidence supporting logging, alerting, and forensic readiness using Wazuh and system-level audit mechanisms.
|
||||
|
||||
## Included Artifacts
|
||||
- Wazuh agent and server logs
|
||||
- SIEM dashboard screenshots
|
||||
- Custom alert rules
|
||||
- Log forwarding rules (if applicable)
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Agent deployment logs available
|
||||
- [ ] Alerts fire on auth failures, sudo, etc.
|
||||
- [ ] Central log retention meets policy
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 💾 Evidence – Backups & Recovery Testing
|
||||
|
||||
## Purpose
|
||||
Documentation of backup routines, tools (Restic/Borg), encrypted vaults, and restore verification processes.
|
||||
|
||||
## Included Artifacts
|
||||
- Restic/Borg configuration files
|
||||
- Restore logs and diffs
|
||||
- Encryption key storage policy
|
||||
- Backup rotation reports
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Encryption is enabled at rest
|
||||
- [ ] Monthly restore test logs present
|
||||
- [ ] Offsite backup location validated
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 📜 Evidence – Policies and Administrative Controls
|
||||
|
||||
## Purpose
|
||||
This section contains administrative control evidence including signed policies, role assignments, and procedure documents.
|
||||
|
||||
## Included Artifacts
|
||||
- Access control policy (AC-1)
|
||||
- Incident response plan
|
||||
- User onboarding/offboarding procedures
|
||||
- Policy acceptance logs
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Policies approved and version controlled
|
||||
- [ ] All users have acknowledged relevant policies
|
||||
- [ ] Procedures align with technical implementation
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
apt update && apt install -y git python3-pip curl ufw
|
||||
pip3 install ansible
|
||||
ufw allow OpenSSH
|
||||
ufw --force enable
|
||||
git clone https://github.com/mtkell/open-cmmc-stack.git /opt/open-cmmc-stack
|
||||
cd /opt/open-cmmc-stack/ansible
|
||||
ansible-playbook -i localhost, secure_ubuntu.yml
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
provider "digitalocean" {
|
||||
token = var.do_token
|
||||
}
|
||||
|
||||
resource "digitalocean_droplet" "secure_host" {
|
||||
name = "cmmc-hardened"
|
||||
region = "nyc3"
|
||||
size = "s-2vcpu-4gb"
|
||||
image = "ubuntu-22-04-x64"
|
||||
ssh_keys = [var.ssh_fingerprint]
|
||||
user_data = file("${path.module}/bootstrap.sh")
|
||||
|
||||
tags = ["cmmc", "secure-host"]
|
||||
}
|
||||
|
||||
output "droplet_ip" {
|
||||
value = digitalocean_droplet.secure_host.ipv4_address
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
do_token = "your_digitalocean_token_here"
|
||||
ssh_fingerprint = "your_local_ssh_key_fingerprint"
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
variable "do_token" {
|
||||
description = "DigitalOcean API token"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "ssh_fingerprint" {
|
||||
description = "Your public SSH key fingerprint registered with DigitalOcean"
|
||||
type = string
|
||||
}
|
||||
Loading…
Reference in New Issue