Skip to content

Commit 122f3c2

Browse files
authored
Merge pull request #1 from cisagov/first-commits
First commits for an Ansible role to install and configure `systemd-resolved`
2 parents c848889 + a3eeb16 commit 122f3c2

File tree

9 files changed

+251
-75
lines changed

9 files changed

+251
-75
lines changed

.github/dependabot.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ updates:
1919
- dependency-name: hashicorp/setup-terraform
2020
- dependency-name: mxschmitt/action-tmate
2121
- dependency-name: step-security/harden-runner
22-
# # Managed by cisagov/skeleton-ansible-role
23-
# - dependency-name: github/codeql-action
22+
# Managed by cisagov/skeleton-ansible-role
23+
- dependency-name: github/codeql-action
2424
package-ecosystem: github-actions
2525
schedule:
2626
interval: weekly
2727

2828
- directory: /
29-
# ignore:
30-
# # Managed by cisagov/skeleton-ansible-role
31-
# - dependency-name: ansible
32-
# - dependency-name: ansible-core
29+
ignore:
30+
# Managed by cisagov/skeleton-ansible-role
31+
- dependency-name: ansible
32+
- dependency-name: ansible-core
3333
package-ecosystem: pip
3434
schedule:
3535
interval: weekly

.pre-commit-config.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,20 @@ repos:
157157
rev: v24.2.0
158158
hooks:
159159
- id: ansible-lint
160+
additional_dependencies:
161+
# Per the documentation and the pre-commit hook
162+
# configuration, ansible-lint does not know about modules
163+
# that live outside of ansible-core. See these links for
164+
# more details:
165+
# - https://github.com/ansible/ansible-lint/blob/main/src/ansiblelint/rules/syntax_check.md#syntax-checkunknown-module
166+
# - https://github.com/ansible/ansible-lint/blob/ad0157eb38059b02d57458504340209f221e3189/.pre-commit-hooks.yaml#L14-L19
167+
#
168+
# Since ansible.posix.mount lives inside of the ansible
169+
# package itself, we must include that package here.
170+
#
171+
# Note also that for consistency's sake we pull in the same
172+
# version of ansible that is used in requirements-test.txt.
173+
- ansible>=8,<10
160174
# files: molecule/default/playbook.yml
161175

162176
# Terraform hooks

README.md

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
[![GitHub Build Status](https://github.com/cisagov/ansible-role-systemd-resolved/workflows/build/badge.svg)](https://github.com/cisagov/ansible-role-systemd-resolved/actions)
44
[![CodeQL](https://github.com/cisagov/ansible-role-systemd-resolved/workflows/CodeQL/badge.svg)](https://github.com/cisagov/ansible-role-systemd-resolved/actions/workflows/codeql-analysis.yml)
55

6-
This is a skeleton project that can be used to quickly get a new
7-
[cisagov](https://github.com/cisagov) Ansible role GitHub project
8-
started. This skeleton project contains
9-
[licensing information](LICENSE), as well as
10-
[pre-commit hooks](https://pre-commit.com) and
11-
[GitHub Actions](https://github.com/features/actions) configurations
12-
appropriate for an Ansible role.
6+
This is an Ansible role that installs and configures
7+
[`systemd-resolved`](https://wiki.archlinux.org/title/systemd-resolved).
8+
It performs the following actions:
9+
10+
- Installs `systemd-resolved` and ensures that `resolvconf` is not
11+
installed.
12+
- Creates an `/etc/resolv.conf` symlink that results in the
13+
`systemd-resolved` stub DNS resolver being used by default for all
14+
system DNS lookups.
1315

1416
## Requirements ##
1517

@@ -42,7 +44,7 @@ where `requirements.yml` looks like:
4244

4345
```yaml
4446
---
45-
- name: skeleton
47+
- name: systemd_resolved
4648
src: https://github.com/cisagov/ansible-role-systemd-resolved
4749
```
4850
@@ -61,18 +63,11 @@ Here's how to use it in a playbook:
6163
become: true
6264
become_method: sudo
6365
tasks:
64-
- name: Include skeleton
66+
- name: Include systemd-resolved
6567
ansible.builtin.include_role:
66-
name: skeleton
68+
name: systemd_resolved
6769
```
6870

69-
## New Repositories from a Skeleton ##
70-
71-
Please see our [Project Setup guide](https://github.com/cisagov/development-guide/tree/develop/project_setup)
72-
for step-by-step instructions on how to start a new repository from
73-
a skeleton. This will save you time and effort when configuring a
74-
new repository!
75-
7671
## Contributing ##
7772

7873
We welcome contributions! Please see [`CONTRIBUTING.md`](CONTRIBUTING.md) for
@@ -93,4 +88,4 @@ with this waiver of copyright interest.
9388

9489
## Author Information ##
9590

96-
First Last - <first.last@gwe.cisa.dhs.gov>
91+
Shane Frasier - <jeremy.frasier@gwe.cisa.dhs.gov>

meta/main.yml

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
# See also cisagov/skeleton-ansible-role#153.
77
dependencies: []
88
galaxy_info:
9-
author: First Last
9+
author: Shane Frasier
1010
company: CISA Cyber Assessments
11-
description: Skeleton Ansible role
11+
description: Install and configure systemd-resolved
1212
galaxy_tags:
13-
- skeleton
13+
- resolved
14+
- systemd
15+
- systemdresolved
1416
license: CC0
1517
# With the release of version 2.10, Ansible finally correctly
1618
# identifies Kali Linux as being the Kali distribution of the Debian
@@ -25,8 +27,9 @@ galaxy_info:
2527
- "2023"
2628
- name: Debian
2729
versions:
28-
- buster
29-
- bullseye
30+
# These platforms do not provide systemd-resolved.
31+
# - buster
32+
# - bullseye
3033
- bookworm
3134
- trixie
3235
- name: Fedora
@@ -36,9 +39,10 @@ galaxy_info:
3639
- name: Kali
3740
versions:
3841
- "2023"
39-
- name: Ubuntu
40-
versions:
41-
- focal
42-
- jammy
43-
role_name: skeleton
42+
# These platforms do not provide systemd-resolved.
43+
# - name: Ubuntu
44+
# versions:
45+
# - focal
46+
# - jammy
47+
role_name: systemd_resolved
4448
standalone: true

molecule/default/molecule.yml

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,25 @@ platforms:
1313
privileged: true
1414
volumes:
1515
- /sys/fs/cgroup:/sys/fs/cgroup:rw
16-
- cgroupns_mode: host
17-
command: /lib/systemd/systemd
18-
image: docker.io/geerlingguy/docker-debian10-ansible:latest
19-
name: debian10-systemd
20-
platform: amd64
21-
pre_build_image: true
22-
privileged: true
23-
volumes:
24-
- /sys/fs/cgroup:/sys/fs/cgroup:rw
25-
- cgroupns_mode: host
26-
command: /lib/systemd/systemd
27-
image: docker.io/geerlingguy/docker-debian11-ansible:latest
28-
name: debian11-systemd
29-
platform: amd64
30-
pre_build_image: true
31-
privileged: true
32-
volumes:
33-
- /sys/fs/cgroup:/sys/fs/cgroup:rw
16+
# These platforms do not provide systemd-resolved.
17+
# - cgroupns_mode: host
18+
# command: /lib/systemd/systemd
19+
# image: docker.io/geerlingguy/docker-debian10-ansible:latest
20+
# name: debian10-systemd
21+
# platform: amd64
22+
# pre_build_image: true
23+
# privileged: true
24+
# volumes:
25+
# - /sys/fs/cgroup:/sys/fs/cgroup:rw
26+
# - cgroupns_mode: host
27+
# command: /lib/systemd/systemd
28+
# image: docker.io/geerlingguy/docker-debian11-ansible:latest
29+
# name: debian11-systemd
30+
# platform: amd64
31+
# pre_build_image: true
32+
# privileged: true
33+
# volumes:
34+
# - /sys/fs/cgroup:/sys/fs/cgroup:rw
3435
- cgroupns_mode: host
3536
command: /lib/systemd/systemd
3637
image: docker.io/geerlingguy/docker-debian12-ansible:latest
@@ -76,24 +77,25 @@ platforms:
7677
privileged: true
7778
volumes:
7879
- /sys/fs/cgroup:/sys/fs/cgroup:rw
79-
- cgroupns_mode: host
80-
command: /lib/systemd/systemd
81-
image: docker.io/geerlingguy/docker-ubuntu2004-ansible:latest
82-
name: ubuntu-20-systemd
83-
platform: amd64
84-
pre_build_image: true
85-
privileged: true
86-
volumes:
87-
- /sys/fs/cgroup:/sys/fs/cgroup:rw
88-
- cgroupns_mode: host
89-
command: /lib/systemd/systemd
90-
image: docker.io/geerlingguy/docker-ubuntu2204-ansible:latest
91-
name: ubuntu-22-systemd
92-
platform: amd64
93-
pre_build_image: true
94-
privileged: true
95-
volumes:
96-
- /sys/fs/cgroup:/sys/fs/cgroup:rw
80+
# These platforms do not provide systemd-resolved.
81+
# - cgroupns_mode: host
82+
# command: /lib/systemd/systemd
83+
# image: docker.io/geerlingguy/docker-ubuntu2004-ansible:latest
84+
# name: ubuntu-20-systemd
85+
# platform: amd64
86+
# pre_build_image: true
87+
# privileged: true
88+
# volumes:
89+
# - /sys/fs/cgroup:/sys/fs/cgroup:rw
90+
# - cgroupns_mode: host
91+
# command: /lib/systemd/systemd
92+
# image: docker.io/geerlingguy/docker-ubuntu2204-ansible:latest
93+
# name: ubuntu-22-systemd
94+
# platform: amd64
95+
# pre_build_image: true
96+
# privileged: true
97+
# volumes:
98+
# - /sys/fs/cgroup:/sys/fs/cgroup:rw
9799
scenario:
98100
name: default
99101
verifier:

molecule/default/prepare.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
11
---
22
- name: Import upgrade playbook
33
ansible.builtin.import_playbook: upgrade.yml
4+
5+
# Docker bind mounts a file from the host to /etc/resolv.conf. This
6+
# is inconvenient for us, since we need to create a symlink at
7+
# /etc/resolv.conf. At the same time, we don't want to break DNS.
8+
# The playbook being imported contains a workaround for this
9+
# situation.
10+
- name: Unmount /etc/resolv.conf
11+
ansible.builtin.import_playbook: unmount.yml
12+
13+
# We require dig for one of our Molecule tests
14+
- name: Install dig
15+
hosts: all
16+
become: true
17+
become_method: ansible.builtin.sudo
18+
tasks:
19+
- name: Install dig
20+
ansible.builtin.package:
21+
name:
22+
- dnsutils

molecule/default/tests/test_default.py

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Standard Python Libraries
44
import os
5+
import re
56

67
# Third-Party Libraries
78
import pytest
@@ -12,7 +13,69 @@
1213
).get_hosts("all")
1314

1415

15-
@pytest.mark.parametrize("x", [True])
16-
def test_packages(host, x):
17-
"""Run a dummy test, just to show what one would look like."""
18-
assert x
16+
def test_packages(host):
17+
"""Verify that the expected packages are installed/uninstalled."""
18+
assert host.package(
19+
"systemd-resolved"
20+
).is_installed, "The package systemd-resolved is not installed."
21+
assert not host.package(
22+
"resolvconf"
23+
).is_installed, "The package resolvconf is installed."
24+
25+
26+
def test_symlink(host):
27+
"""Verify that /etc/resolv.conf is the expected symlink."""
28+
f = host.file("/etc/resolv.conf")
29+
assert f.is_symlink, "/etc/resolv.conf is not a symlink."
30+
31+
if host.system_info.distribution in ["amzn"]:
32+
# /run/systemd/resolve/stub-resolv.conf is a symlink to
33+
# /run/systemd/resolve/resolv.conf in AL2023, so the
34+
# /etc/resolv.conf symlink resolves to the latter.
35+
symlink_target = "/run/systemd/resolve/resolv.conf"
36+
else:
37+
symlink_target = "/run/systemd/resolve/stub-resolv.conf"
38+
39+
assert (
40+
f.linked_to == symlink_target
41+
), f"/etc/resolv.conf is not a symlink to {symlink_target}."
42+
43+
44+
def test_services(host):
45+
"""Verify that the expected services are present."""
46+
s = host.service("systemd-resolved")
47+
# TODO - This assertion currently fails because of
48+
# pytest-dev/pytest-testinfra#757. Once
49+
# pytest-dev/pytest-testinfra#754 has been merged and a new
50+
# release is created the following line can be uncommented.
51+
#
52+
# See #3 for more details.
53+
# assert s.exists, "systemd-resolved service does not exist."
54+
assert s.is_enabled, "systemd-resolved service is not enabled."
55+
assert s.is_running, "systemd-resolved service is not running."
56+
57+
58+
@pytest.mark.parametrize(
59+
"dig_command",
60+
[
61+
"www.yahoo.com",
62+
"AAAA www.yahoo.com",
63+
],
64+
)
65+
def test_dns_resolution(host, dig_command):
66+
"""Verify that the systemd-resolved resolver is being used by default."""
67+
cmd = host.run(f"dig {dig_command}")
68+
assert cmd.rc == 0, f"Command dig {dig_command} did not exit successfully."
69+
# AL2023 is funky. /run/systemd/resolve/stub-resolv.conf is
70+
# itself a symlink to /run/systemd/resolve/resolv.conf, which
71+
# points directly to the nameserver obtained from DNS. I don't
72+
# know why it does this, but our testing must work around it.
73+
if host.system_info.distribution in ["amzn"]:
74+
pass
75+
else:
76+
# Verify that the dig result came from the systemd-resolved
77+
# service.
78+
assert (
79+
re.search(r"^;; SERVER: 127\.0\.0\.53#53", cmd.stdout, re.MULTILINE)
80+
is not None
81+
), f"Command dig {dig_command} did not return a results from 127.0.0.53."

molecule/default/unmount.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
- name: Unmount /etc/resolv.conf
3+
hosts: all
4+
become: true
5+
become_method: ansible.builtin.sudo
6+
tasks:
7+
- name: >-
8+
Grab the current owner, group, and mode for the existing
9+
/etc/resolv.conf
10+
ansible.builtin.stat:
11+
follow: true
12+
path: /etc/resolv.conf
13+
register: resolv_conf
14+
15+
- name: Copy /etc/resolv.conf to /tmp, preserving owner, group, and mode
16+
ansible.builtin.copy:
17+
dest: /tmp/resolv.conf
18+
group: "{{ resolv_conf.stat.gid }}"
19+
mode: "{{ resolv_conf.stat.mode }}"
20+
owner: "{{ resolv_conf.stat.uid }}"
21+
remote_src: true
22+
src: /etc/resolv.conf
23+
24+
- name: Unmount /etc/resolv.conf
25+
ansible.posix.mount:
26+
path: /etc/resolv.conf
27+
state: unmounted
28+
29+
- name: Copy /tmp/resolv.conf to /etc, preserving owner, group, and mode
30+
ansible.builtin.copy:
31+
dest: /etc/resolv.conf
32+
group: "{{ resolv_conf.stat.gid }}"
33+
mode: "{{ resolv_conf.stat.mode }}"
34+
owner: "{{ resolv_conf.stat.uid }}"
35+
remote_src: true
36+
src: /tmp/resolv.conf

0 commit comments

Comments
 (0)