LXD 2.0 auto-creates client.crt and client.key, but newer LXD versions do not. How do I force creation of the client key pair?

Hi,

Short(er) version

How can I force the creation of a new key/cert for versions of LXD newer than 2.0 without having to first install LXD 2.0 and launch a test container?

Example output from a 2.0 installation:

[redhat@centos7-test lxd]$ lxc init images:centos/6/amd64 testing
Generating a client certificate. This may take a minute...
Creating testing

If I go with a fresh installation of LXD newer than 2.0 client cert/key files do not appear to be automatically created.

If I understand this post to the dev list correctly, this change in behavior is intentional.

Details

I’m still fairly new to LXD and am primarily using LXD 2.0 and 3.0 for testing Ansible playbooks.

I’ve been able to use Ansible + lxd_container and lxd_profile to manage LXD profiles and containers without issue on Ubuntu 16.04 and newer using APT-based and snap-based installations. For UNIX sockets it was mostly straightforward once I figured out the difference in location (/var/lib/lxd/unix.socket vs /var/snap/lxd/common/lxd/unix.socket).

I had a lot of trouble getting REST API connectivity working via https://127.0.0.1:8443 until I found some Ansible GitHub issues noting that the client cert and key were still required even when providing the trust password. For whatever reason my test Ubuntu 16.04 systems already had the key pair, likely as a result of installing LXD 2.0 before going back and enabling the backports repo to gain access to 3.0.3 LTS packages.

For CentOS 7 I struggled similarly, until I went through these steps which resulted in the desired key/cert files and a fully updated LXD installation:

  1. sudo snap install lxd --channel=2.0/stable
  2. sudo /var/lib/snapd/snap/bin/lxd init
  3. lxc init images:centos/6/amd64 testing
  4. sudo snap refresh lxd --channel=stable

I then had to follow the steps provided on this thread to apply the required namespace changes:

grubby --args="user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)"
grubby --args="namespace.unpriv_enable=1" --update-kernel="$(grubby --default-kernel)"
echo "user.max_user_namespaces=3883" > /etc/sysctl.d/99-userns.conf
reboot

That specific set of steps results in me being able to manage LXD profiles and containers from Ansible.

Thanks in advance for reading this and for any tips/tricks that you may have.

1 Like

The lxc command only needs a client.crt/client.key pair when connecting to a remote private LXD instance over HTTPs.

In the past (2.0) we were being a bit lazy and just always generated the keypair if missing, in newer releases, we decided to stop burning CPU needlessly and instead will only generate the keypair the first time you use lxc remote add to add such a remote LXD server.

So short answer is run lxc remote add with the URL of a remote LXD server and without passing --public and you’ll get a keypair generated.

Thank you for your reply!

What about Ansible + lxd_* modules which rely on REST API connections? It seems that if you opt to connect via https://127.0.0.1:8443 then the client cert/key are also needed (unless I’m doing something entirely wrong, which is certain possible).

Is this something specific to Ansible, perhaps a bug in the module itself which is enforcing this requirement?

Not invalidating my comments prior to this, just responding to a different portion of your last reply:

So short answer is run lxc remote add with the URL of a remote LXD server and without passing --public and you’ll get a keypair generated.

I figured I’d try adding the HTTPS REST API URL for the local listening daemon and sure enough (no surprise to you), that is sufficient to generate the key/cert:

$ lxc remote add local-rest-api https://127.0.0.1:8443
Generating a client certificate. This may take a minute...
Certificate fingerprint: 63598209239c37d82eff529b459d07560831d63d7bb67b1ed1b68a27c4404503
ok (y/n)? y
Admin password for local-rest-api: 
Client certificate stored at server:  local-rest-api

I wasn’t sure what “Admin password” was, so I entered the same credentials I entered earlier for the “trust password” when running sudo /var/lib/snapd/snap/bin/lxd init.

This is good to know and answers my main question.

To recap/expand on my earlier question, if I want to connect to 127.0.0.1:8443 from the same box, what is absolutely required?

  • Client cert (seems like it)
  • Client key (seems like it)
  • Trust password?

My use case is Ansible + lxd_* modules, but I’m not sure if the modules are applying additional requirements outside what LXD already has.

Thanks again for your help.

1 Like