canonical / cloud-init

Official upstream for the cloud-init: cloud instance initialization
https://cloud-init.io/
Other
3.02k stars 889 forks source link

Apt configure doesn't set up custom keys for primary/security on Noble #5473

Open KellenRenshaw opened 5 months ago

KellenRenshaw commented 5 months ago

Bug report

When using the "apt:" module to configure a local mirror for the "primary" and "security" keys, if the mirror is signed by a local key, the rendered ubuntu.sources file still has "Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg" instead of pointing to the file presumably generated from the "key" key.

Steps to reproduce the problem

Attempt to use a local mirror signed with a non-standard key, like so:

config:
  user.user-data: |
    #cloud-config
    apt:
      primary:
        - arches: [default]
          uri: http://apt.example.net/ubuntu/
          key: |
            -----BEGIN PGP PUBLIC KEY BLOCK-----
           <snip>

Launch a Noble container with "apt update" in the runcmd, it will fail on validating the GPG signatures with: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY

Environment details

MiRiskyy commented 5 months ago
apt:
  primary:
    - arches: [default]
      uri: http://apt.example.net/ubuntu/
      keyid: ABCDEF1234 # Specify key ID instead of inline key
      keyserver: http://my.keyserver.example/

The issue seems to be that specifying the inline PGP key is not properly configuring the APT sources to use that key. Instead, specify the key

stew3254 commented 5 months ago

It also doesn't work with sources

#cloud-config
apt:
  preserve_sources_list: false
  sources:
    ubuntu.sources:
      append: false
      filename: ubuntu.sources
      source: <uri>
      key: |
        <key>
zypA13510 commented 4 months ago

Not sure if related, but I just resolved an issue with inline PGP key on Noble.

In my case, the output log says

Decode error, failed to add key: [key]

The original config that failed with this error:

apt:
  sources:
    docker.list:
      key: |
        -----BEGIN PGP PUBLIC KEY BLOCK-----
        mQINBFit2ioBEADhWpZ8/wvZ6hUTiXOwQHXMAlaFHcPH9hAtr4F1y2+OYdbtMuth
        ...
        -----END PGP PUBLIC KEY BLOCK-----

After changing it to the one below the issue is resolved. It might have to do with the extra line after "begin block".

apt:
  sources:
    docker.list:
      key: |
        -----BEGIN PGP PUBLIC KEY BLOCK-----
        Comment: 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88

        mQINBFit2ioBEADhWpZ8/wvZ6hUTiXOwQHXMAlaFHcPH9hAtr4F1y2+OYdbtMuth
        ...
        -----END PGP PUBLIC KEY BLOCK-----
TheRealFalcon commented 4 months ago

The lack of a newline does create a problem. From the OpenPGP Message Format RFC:

Concatenating the following data creates ASCII Armor:

  • An Armor Header Line, appropriate for the type of data
  • Armor Headers
  • A blank (zero-length, or containing only whitespace) line
  • The ASCII-Armored data
  • An Armor Checksum
  • The Armor Tail, which depends on the Armor Header Line

(emphasis mine)

While some gpg implementations can deal with such issues, you'll still get errors. If you try to gpg --dearmor your key on the command line, you'll should see something like gpg: invalid armor header: ... along with your data.

Given that we don't want cloud-init to masking errors, I think that this works as expected.

TheRealFalcon commented 4 months ago

I have noticed that cloud-init gives some garbage errors when this happens, so we can certainly update the logs and output of cloud-init status --long to make it clear that gpg dearmoring failed rather than the current stuff about failing to encode binary data.

KellenRenshaw commented 4 months ago

I have tested on Noble with using the keyid/keyserver method, and that fails also. Of interest is this:

2024-07-29 19:52:50,448 - util.py[DEBUG]: Writing to /etc/apt/trusted.gpg.d/security.gpg - wb: [644] 2198 bytes
2024-07-29 19:52:50,452 - cc_apt_configure.py[INFO]: No custom template provided, fall back to builtin
2024-07-29 19:52:50,452 - util.py[DEBUG]: Reading from /etc/cloud/templates/sources.list.ubuntu.deb822.tmpl (quiet=False)
2024-07-29 19:52:50,452 - util.py[DEBUG]: Read 3019 bytes from /etc/cloud/templates/sources.list.ubuntu.deb822.tmpl

It seems to want a template, but I didn't find a reference in the documentation.

KellenRenshaw commented 4 months ago

Turns out the value is hardcoded in the template present in templates/sources.list.ubuntu.deb822.tmpl. This should probably be a variable, but I am not sure how to go about adding that capability.