gRPC - message interchange format and interface definition language. Protocol Buffers - platform-neutral extensible mechanisms for serializing structured data, default for gRPC.
Keycloak
Tcpdump, Wireshark
Intrusion Detection, Prevention System (IDS, IPS)
SysAdmin, Audit, Network, Security tools list
OCI (Open Container Initiative) low level, runtime specification and high level, image specification have standardized what was initially a mess.
Containerd, Docker, CRI-O, podman are high level since they implement at least parts of the image specification. Runc, Crun, gVisor, Firecracker implement the low level runtime specification that runs processes in the container.
Containerd architecture schema.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Docker CLI] [ Docker API ] [ Build ]
Integrated Lifecycle
[ Compose ] [Content Trust [Authentication] Management
and verification]
[ Security ] [ Network ] [ Volumes ] Docker
[ Containerd [RUNC] ] Container runtime
------------------------------------------------ OCI
[ Linux ][ Windows ] OS
[ Hardware ][ Cloud ] Infrastructure
Runc is written in Go. Crun is an alternative that needs fewer resources and is favored by Red Hat, written in C.
Firecracker by AWS (Rust) has hardware enforced isolation via KVM. Google's gVisor has better Kubernetes and Docker integration, less overhead but less strict isolation (sandbox).
containerd offers a fully namespaced API so multiple consumers can all use a single containerd instance without conflicting with one another in a single daemon. To inspect container
1
2
3
ctr namespaces
ctr leases --help
ctr -n docker tasks
Create a default OCI configuration.
1
runc spec && less config.json
Configure runc (enter namespace)
1
nsenter --help
1
2
3
4
5
6
7
docker run --help
docker run hello-world
docker pull rockylinux/rockylinux:10-ubi-micro
docker images
docker history rockylinux/rockylinux:10-ubi-micro
docker inspect minikube
docker exec --tty minikube sh -c 'uname -a'
Run uv using docker
1
docker run --rm -it ghcr.io/astral-sh/uv:debian uv --help
Also compatible with docker-compose
alias docker=podman
1
podman
nerdctl, CLI for containerd.
Turn docker-compose files into flowcharts with docker-compose-viz-mermaid
1
docker run --rm -v $(PWD):/data derlin/docker-compose-viz-mermaid /data/docker-compose.yml -f png
TeamsSix container escape check script. Deepce Docker Enumeration, Escalation of Privileges and Container Escapes
Genuine vulnerabilities exist but misconfiguration is a more likely way to escape a container.
First, figure out if you're in a container.
1
2
3
4
ls -la / | grep dockerenv
cat /proc/1/cgroup
env | grep -i kube
env | grep -i docker
--privileged container detection in the containerNon-privileged containers can't create network interfaces.
1
ip link add dummy0 type dummy
List disks, mount the host root file system and other nested ones as needed, chroot into the host.
1
2
3
4
5
6
7
8
fdisk -l
mount /dev/sda4 /mnt/hostroot
... snip ...
chroot /mnt/hostroot bash
id
1
uid=0(root) gid=0(root) groups=0(root)
1
2
capsh --print
cat /proc/self/status | grep Cap
Generate config defaults, all commented.
1
2
ansible-config init --disabled > ansible.cfg
ansible-config init --disabled -t all > ansible_full.cfg
Specify and install requirements.
1
2
ansible-galaxy install -r requirements.yml # roles
ansible-galaxy collection install -r requirements.yml # collections
1
2
3
4
5
6
7
8
9
10
11
#requirements.yml
---
roles:
- src: https://my.scm.com/my-ansible-roles/role1.git
scm: git
version: master
name: role1
collections:
# simple notation
- community.libvirt
Specify requirements for roles in role1/meta/main.yml using the same notation as in requirements.yml
1
2
3
4
5
6
7
8
9
10
11
ansible-galaxy collection list
ansible-galaxy list
ansible-galaxy search
ansible-pull --only-if-changed --verify-commit site.yml
ansible-inventory -i inventory/ --list
# count changes
ansible-playbook site.yml | grep -oE "changed=*[0-9]" | cut -d '=' -f 2
# get guest vm status using community.libvirt.virt module
ansible localhost -m virt -a "name=vm_name command=status"
# quick fact overview
ansible --inventory inventory/ srv-web -m ansible.builtin.setup
Loops have the default loop_var item but that can be renamed in case of a conflict. loop_control has other uses and does not affect until.
1
2
3
4
5
6
7
community.digitalocean.digital_ocean:
name: "{{ server }}"
state: present
loop: "{{ servers }}"
loop_control:
loop_var: server
pause: 3
Lookup current loop_var:
1
"{{ lookup('vars', ansible_loop_var) }}"
Inspect:
1
{{ servers | type_debug }}
1
2
ansible-playbook ansible_test_jinja2_template.yml --diff \
--extra-vars="@kvmlab/roles/web_server/defaults/main.yml"
1
2
3
4
5
6
7
8
# playbook to test jinja2 template
---
- hosts: 127.0.0.1
tasks:
- name: Test jinja2template
template:
src: "kvmlab/roles/web_server/templates/nginx.conf.j2"
dest: "test.conf"
1
2
3
4
5
ansible-playbook --syntax-check kvm_provision.yml
yamllint -d relaxed kvm_provision.yml
ansible-lint kvm_provision.yml # recursive check descending to roles
ansible-playbook --ask-become-pass kvm_provision.yml --extra-vars vm=web01
ansible-playbook -K kvm_provision.yml -e vm=web01 -e net=br0
Ansible-playbook error YAML parsing failed: Colons in unquoted values must be followed by a non-space character.
is likely caused by an indentation error.
Playbooks contain plays as top level elements, for using roles, tasks keywords.
1
2
3
4
5
6
7
8
9
10
11
12
# site.yml
---
- name: Prepare KVM host
hosts: kvm # ansible group name from inventory
gather_facts: yes
become: yes
roles:
- kvm_host
post_tasks:
- name: Print ansible_hostname
ansible.builtin.debug:
var: ansible_hostname
Ansible loads inventory sources in the order you supply them. It defines hosts, groups, and variables as it encounters them in the source files, adding the all and ungrouped groups at the end if needed.
1
2
3
4
# inventory/test.yml
# Keep the inventory ordering!
kvm:
hosts: localhost
1
ansible-playbook -K -i inventory/ site.yml
List of modules that only run when source changed:
ansible.builtin.templateansible.builtin.copy # copy acts like rsync regarding /List of modules that ensure state only when parameter state is used:
ansible.builtin.dnfCreate your new role:
1
ansible-galaxy role init kvm_provision
1
2
3
4
5
6
# roles/webapp/tasks/main.yml
---
- name: Include monitoring role conditionally
ansible.builtin.include_role:
name: monitoring
when: webapp_enable_monitoring | default(true) | bool
meta/main.yml using a feature flag1
2
3
4
5
# roles/webapp/meta/main.yml
dependencies:
- role: monitoring
vars:
monitoring_enabled: "{{ webapp_enable_monitoring | default(true) }}"
1
2
3
4
5
6
7
8
# roles/monitoring/tasks/main.yml
# Skip all tasks if monitoring is disabled
---
- name: Install monitoring agent
ansible.builtin.dnf:
name: monitoring-agent
state: present
when: monitoring_enabled | bool
1
docsible --role roles/kvm_provision/ --playbook kvm_provision.yml --no-backup --graph
Debug output can also include secret information despite no_log settings being enabled.
Put the encrypt_string result in a vars file like vault.yml containing secrets to see clearly which secrets are which. Add vault.yml to .gitignore
1
2
3
ansible-vault create secrets_file.enc # no secret name recorded
ansible-vault encrypt_string 'supersecret1' --name 'vault_root_pass' >> vault.yml
ansible-playbook -i inventory.ini -e @vault.yml --vault-password-file password_file kvm_provision.yml
Example lookup from Hashicorp Vault
1
2
3
4
- name: Ensure API key is present in config file
ansible.builtin.lineinfile:
path: /etc/app/configuration.ini
line: "API_KEY={{ lookup('hashi_vault', 'secret=config-secrets/data/app/api-key:data token=s.FOmpGEHjzSdxGixLNi0AkdA7 url=http://localhost:8201')['key'] }}"
Special reserved tags are always, never, tagged, untagged and all. Both always and never are used for tagging, others for selecting which tags to run or skip.
1
2
ansible-playbook example.yml --list-tags
ansible-playbook example.yml --tags "configuration,packages" --list-tasks
Define the tags at the level of your play or block, or when you add a role or import a file. Ansible applies the tags down the dependency chain to all child tasks.
Fact gathering is an implicit task tagged with always so that runs in addition to tagged tasks by default.