Skip to content

Commit c3dbc64

Browse files
authored
Merge pull request #21 from stackhpc/ubuntu-repos
Backport Apt repository configuration (Wallaby)
2 parents 7880c40 + 20e6afd commit c3dbc64

File tree

15 files changed

+375
-17
lines changed

15 files changed

+375
-17
lines changed

ansible/group_vars/all/apt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,38 @@ apt_proxy_http:
1010

1111
# Apt proxy URL for HTTPS. Default is {{ apt_proxy_http }}.
1212
apt_proxy_https: "{{ apt_proxy_http }}"
13+
14+
# List of Apt configuration options. Each item is a dict with the following
15+
# keys:
16+
# * content: free-form configuration file content
17+
# * filename: name of a file in /etc/apt/apt.conf.d/ in which to write the
18+
# configuration
19+
# Default is an empty list.
20+
apt_config: []
21+
22+
# List of apt keys. Each item is a dict containing the following keys:
23+
# * url: URL of key
24+
# * filename: Name of a file in which to store the downloaded key. The
25+
# extension should be '.asc' for ASCII-armoured keys, or '.gpg' otherwise.
26+
# Default is an empty list.
27+
apt_keys: []
28+
29+
# A list of Apt repositories. Each item is a dict with the following keys:
30+
# * types: whitespace-separated list of repository types, e.g. deb or deb-src
31+
# (optional, default is 'deb')
32+
# * url: URL of the repository
33+
# * suites: whitespace-separated list of suites, e.g. focal (optional, default
34+
# is ansible_facts.distribution_release)
35+
# * components: whitespace-separated list of components, e.g. main (optional,
36+
# default is 'main')
37+
# * signed_by: whitespace-separated list of names of GPG keyring files in
38+
# apt_keys_path (optional, default is unset)
39+
# * architecture: whitespace-separated list of architectures that will be used
40+
# (optional, default is unset)
41+
# Default is an empty list.
42+
apt_repositories: []
43+
44+
# Whether to disable repositories in /etc/apt/sources.list. This may be used
45+
# when replacing the distribution repositories via apt_repositories.
46+
# Default is false.
47+
apt_disable_sources_list: false

ansible/roles/apt/defaults/main.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,41 @@ apt_proxy_http:
1010

1111
# Apt proxy URL for HTTPS. Default is {{ apt_proxy_http }}.
1212
apt_proxy_https: "{{ apt_proxy_http }}"
13+
14+
# List of Apt configuration options. Each item is a dict with the following
15+
# keys:
16+
# * content: free-form configuration file content
17+
# * filename: name of a file in /etc/apt/apt.conf.d/ in which to write the
18+
# configuration
19+
# Default is an empty list.
20+
apt_config: []
21+
22+
# Directory containing GPG keyrings for apt repos.
23+
apt_keys_path: "/usr/local/share/keyrings"
24+
25+
# List of apt keys. Each item is a dict containing the following keys:
26+
# * url: URL of key
27+
# * filename: Name of a file in which to store the downloaded key. The
28+
# extension should be '.asc' for ASCII-armoured keys, or '.gpg' otherwise.
29+
# Default is an empty list.
30+
apt_keys: []
31+
32+
# A list of Apt repositories. Each item is a dict with the following keys:
33+
# * types: whitespace-separated list of repository types, e.g. deb or deb-src
34+
# (optional, default is 'deb')
35+
# * url: URL of the repository
36+
# * suites: whitespace-separated list of suites, e.g. focal (optional, default
37+
# is ansible_facts.distribution_release)
38+
# * components: whitespace-separated list of components, e.g. main (optional,
39+
# default is 'main')
40+
# * signed_by: whitespace-separated list of names of GPG keyring files in
41+
# apt_keys_path (optional, default is unset)
42+
# * architecture: whitespace-separated list of architectures that will be used
43+
# (optional, default is unset)
44+
# Default is an empty list.
45+
apt_repositories: []
46+
47+
# Whether to disable repositories in /etc/apt/sources.list. This may be used
48+
# when replacing the distribution repositories via apt_repositories.
49+
# Default is false.
50+
apt_disable_sources_list: false
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
- name: Update apt cache
3+
package:
4+
update_cache: true
5+
become: true

ansible/roles/apt/tasks/config.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
- name: Ensure Apt is configured
3+
copy:
4+
content: "{{ item.content }}"
5+
dest: "/etc/apt/apt.conf.d/{{ item.filename }}"
6+
owner: root
7+
group: root
8+
mode: 0664
9+
loop: "{{ apt_config }}"
10+
loop_control:
11+
label: "{{ item.filename }}"
12+
become: true
13+
notify:
14+
- Update apt cache

ansible/roles/apt/tasks/keys.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
- name: Ensure keys directory exists
3+
file:
4+
path: "{{ apt_keys_path }}"
5+
owner: root
6+
group: root
7+
mode: 0755
8+
state: directory
9+
become: true
10+
11+
- name: Ensure keys exist
12+
get_url:
13+
url: "{{ item.url }}"
14+
dest: "{{ apt_keys_path ~ '/' ~ item.filename | basename }}"
15+
owner: root
16+
group: root
17+
mode: 0644
18+
loop: "{{ apt_keys }}"
19+
become: true

ansible/roles/apt/tasks/main.yml

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
11
---
2-
- name: Configure apt proxy
3-
template:
4-
src: "01proxy.j2"
5-
dest: /etc/apt/apt.conf.d/01proxy
6-
owner: root
7-
group: root
8-
mode: 0664
9-
become: true
10-
when: apt_proxy_http | default('', true) | length > 0 or apt_proxy_https | default('', true) | length > 0
2+
- import_tasks: proxy.yml
113

12-
- name: Remove old apt proxy config
13-
file:
14-
path: /etc/apt/apt.conf.d/01proxy
15-
state: absent
16-
become: true
17-
when: apt_proxy_http | default('', true) | length == 0 and apt_proxy_https | default('', true) | length == 0
4+
- import_tasks: config.yml
5+
6+
- import_tasks: keys.yml
7+
8+
- import_tasks: repos.yml

ansible/roles/apt/tasks/proxy.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
- name: Configure apt proxy
3+
template:
4+
src: "01proxy.j2"
5+
dest: /etc/apt/apt.conf.d/01proxy
6+
owner: root
7+
group: root
8+
mode: 0664
9+
become: true
10+
when: apt_proxy_http | default('', true) | length > 0 or apt_proxy_https | default('', true) | length > 0
11+
12+
- name: Remove old apt proxy config
13+
file:
14+
path: /etc/apt/apt.conf.d/01proxy
15+
state: absent
16+
become: true
17+
when: apt_proxy_http | default('', true) | length == 0 and apt_proxy_https | default('', true) | length == 0

ansible/roles/apt/tasks/repos.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
# NOTE(mgoddard): Use the modern deb822 repository format rather than the old
3+
# format used by the apt_repository module.
4+
- name: Configure apt repositories
5+
template:
6+
src: "kayobe.sources.j2"
7+
dest: "/etc/apt/sources.list.d/kayobe.sources"
8+
owner: root
9+
group: root
10+
mode: 0644
11+
become: true
12+
notify:
13+
- Update apt cache
14+
15+
- name: Disable repositories in /etc/apt/sources.list
16+
replace:
17+
# Make a backup, in case we end up with a broken configuration.
18+
backup: true
19+
path: /etc/apt/sources.list
20+
regexp: '^(deb.*)'
21+
replace: '# \1'
22+
when: apt_disable_sources_list | bool
23+
become: true
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# {{ ansible_managed }}
2+
3+
{% for repo in apt_repositories %}
4+
Types: {{ repo.types | default('deb') }}
5+
URIs: {{ repo.url }}
6+
Suites: {{ repo.suites | default(ansible_facts.distribution_release) }}
7+
Components: {{ repo.components | default('main') }}
8+
{% if repo.signed_by is defined %}
9+
Signed-by: {{ apt_keys_path }}/{{ repo.signed_by }}
10+
{% endif %}
11+
{% if repo.architecture is defined %}
12+
Architecture: {{ repo.architecture }}
13+
{% endif %}
14+
15+
{% endfor %}

doc/source/configuration/reference/hosts.rst

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,19 +298,132 @@ oversight or testing.
298298
Apt
299299
===
300300

301-
On Ubuntu, Apt is used to manage packages and package repositories. Currently
302-
Kayobe does not provide support for configuring custom Apt repositories.
301+
On Ubuntu, Apt is used to manage packages and package repositories.
303302

304303
Apt cache
305304
---------
306305

307306
The Apt cache timeout may be configured via ``apt_cache_valid_time`` (in
308307
seconds) in ``etc/kayobe/apt.yml``, and defaults to 3600.
309308

309+
Apt proxy
310+
---------
311+
310312
Apt can be configured to use a proxy via ``apt_proxy_http`` and
311313
``apt_proxy_https`` in ``etc/kayobe/apt.yml``. These should be set to the full
312314
URL of the relevant proxy (e.g. ``http://squid.example.com:3128``).
313315

316+
Apt configuration
317+
-----------------
318+
319+
Arbitrary global configuration options for Apt may be defined via the
320+
``apt_config`` variable in ``etc/kayobe/apt.yml`` since the Yoga release. The
321+
format is a list, with each item mapping to a dict/map with the following
322+
items:
323+
324+
* ``content``: free-form configuration file content
325+
* ``filename``: name of a file in ``/etc/apt/apt.conf.d/`` in which to write
326+
the configuration
327+
328+
The default of ``apt_config`` is an empty list.
329+
330+
For example, the following configuration tells Apt to use 2 attempts when
331+
downloading packages:
332+
333+
.. code-block:: yaml
334+
335+
apt_config:
336+
- content: |
337+
Acquire::Retries 1;
338+
filename: 99retries
339+
340+
Apt repositories
341+
----------------
342+
343+
Kayobe supports configuration of custom Apt repositories via the
344+
``apt_repositories`` variable in ``etc/kayobe/apt.yml`` since the Yoga release.
345+
The format is a list, with each item mapping to a dict/map with the following
346+
items:
347+
348+
* ``types``: whitespace-separated list of repository types, e.g. ``deb`` or
349+
``deb-src`` (optional, default is ``deb``)
350+
* ``url``: URL of the repository
351+
* ``suites``: whitespace-separated list of suites, e.g. ``focal`` (optional,
352+
default is ``ansible_facts.distribution_release``)
353+
* ``components``: whitespace-separated list of components, e.g. ``main``
354+
(optional, default is ``main``)
355+
* ``signed_by``: whitespace-separated list of names of GPG keyring files in
356+
``apt_keys_path`` (optional, default is unset)
357+
* ``architecture``: whitespace-separated list of architectures that will be used
358+
(optional, default is unset)
359+
360+
The default of ``apt_repositories`` is an empty list.
361+
362+
For example, the following configuration defines a single Apt repository:
363+
364+
.. code-block:: yaml
365+
:caption: ``apt.yml``
366+
367+
apt_repositories:
368+
- types: deb
369+
url: https://example.com/repo
370+
suites: focal
371+
components: all
372+
373+
In the following example, the Ubuntu Focal 20.04 repositories are consumed from
374+
a local package mirror. The ``apt_disable_sources_list`` variable is set to
375+
``true``, which disables all repositories in ``/etc/apt/sources.list``,
376+
including the default Ubuntu ones.
377+
378+
.. code-block:: yaml
379+
:caption: ``apt.yml``
380+
381+
apt_repositories:
382+
- url: http://mirror.example.com/ubuntu/
383+
suites: focal focal-updates
384+
components: main restricted universe multiverse
385+
- url: http://mirror.example.com/ubuntu/
386+
suites: focal-security
387+
components: main restricted universe multiverse
388+
389+
apt_disable_sources_list: true
390+
391+
Apt keys
392+
--------
393+
394+
Some repositories may be signed by a key that is not one of Apt's trusted keys.
395+
Kayobe avoids the use of the deprecated ``apt-key`` utility, and instead allows
396+
keys to be downloaded to a directory. This enables repositories to use the
397+
``SignedBy`` option to state that they are signed by a specific key. This
398+
approach is more secure than using globally trusted keys.
399+
400+
Keys to be downloaded are defined by the ``apt_keys`` variable. The format is a
401+
list, with each item mapping to a dict/map with the following items:
402+
403+
* ``url``: URL of key
404+
* ``filename``: Name of a file in which to store the downloaded key in
405+
``apt_keys_path``. The extension should be ``.asc`` for ASCII-armoured keys,
406+
or ``.gpg`` otherwise.
407+
408+
The default value of ``apt_keys`` is an empty list.
409+
410+
In the following example, a key is downloaded, and a repository is configured
411+
that is signed by the key.
412+
413+
.. code-block:: yaml
414+
:caption: ``apt.yml``
415+
416+
apt_keys:
417+
- url: https://example.com/GPG-key
418+
filename: example-key.asc
419+
420+
apt_repositories:
421+
- types: deb
422+
url: https://example.com/repo
423+
suites: focal
424+
components: all
425+
signed_by: example-key.asc
426+
314427
SELinux
315428
=======
316429
*tags:*

0 commit comments

Comments
 (0)