RBAC Using Candid: Using Candid to add users to MAAS
Candid & Canonical-RBAC
Candid
Candid is an open source, macaroon-based authentication service, written in Go, that supports multiple backends as a source of authentication. It can be used to provide authentication to LXD, Juju, and MAAS.
Candid supports a variety of identity providers including:
- ADFS
- Azure
- Keycloak
- Keystone
- LDAP
- OpenID
- UbuntuOne
- Static
Canonical-RBAC
The Canonical RBAC service is an external service to MAAS that extends the functionality of MAAS and provides role-based access control. Written in Python, RBAC is closed source. The private license requires Ubuntu Advantage to be gain access to the private PPA.
RBAC uses Candid as an authentication source, and sports a nice UI.
Launch a VM
For the lab, we will need a machine (preferably not a container) where we can deploy MAAS. 2vCPU with 4G would be ideal but you can probably get away with half. A t2.medium on AWS works pretty well. Must be amd64. You will need access to port 5240 (MAAS), and 8081 (candid), and 5000 (RBAC) in addition to port 22 (ssh). Or use sshuttle to tunnel into the VM.
Install MAAS For Testing
Create a script with some important variables:
$ cat <<EOF> ~/somevars.sh
MAAS_PW=SomePassword
CANDID_PW=SomePassword
RBAC_PW=SomePassword
PG_VIP=127.0.0.1
MAAS_VIP=12.34.56.78 # external host/IP you access MAAS with
CANDID_DB=postgres://candid:\$CANDID_PW@\$PG_VIP/candid
CANDID_URL=http://\$MAAS_VIP:8081
RBAC_DB=postgres://rbac:\$RBAC_PW@\$PG_VIP/rbac
RBAC_URL=http://\$MAAS_VIP:5000
export CANDID_DB CANDID_URL RBAC_DB RBAC_URL
EOF
$ source ~/somevars.sh
Install MAAS
MAAS doesn’t have a latest/stable channel. When we leave off the channel, we get the latest supported version. This allows us to track updates for that specific version and upgrade to newer versions at our convenience.
$ sudo snap install maas --channel=3.2/stable
Install PostgreSQL
There is a snap called maas-test-db that sets up a PostgreSQL database specially designed for a quick MAAS test but the canonical-rbac install will ensure the postgresql package is installed so we might as well use it.
$ sudo apt update
$ sudo apt install -y postgresql
$ sudo -u postgres psql -c "create user maas
with encrypted password 'mysecretmaaspw'"
$ sudo -u postgres createdb -O maas maasdb
$ PGVER=$(ls -1 /etc/postgresql | tail -1)
$ echo -e "\nhost maasdb maas 0/0 md5" |
sudo tee -a /etc/postgresql/$PGVER/main/pg_hba.conf
Initialize MAAS
Point MAAS at the DB:
$ sudo maas init region+rack \
--database-uri "postgres://maas:mysecretmaaspw@localhost/maasdb"
Create an admin user:
$ sudo maas createadmin --username=root --email=foo@example.com \
--password=$MAAS_PW
Log in:
$ maas login root http://$MAAS_VIP:5240/MAAS/ \
$(sudo maas apikey --username=root | tee maas-api)
Test MAAS
$ maas root tags read
Success.
Machine-readable output follows:
[
{
"name": "virtual",
"definition": "",
"comment": "",
"kernel_opts": "",
"resource_uri": "/MAAS/api/2.0/tags/virtual/"
}
]
Install Candid & Canonical-RBAC
Configure APT
Find Canonical RBAC ppa. This should be listed in https://launchpad.net/~/+archivesubscriptions for all Canonical employees. Be sure to choose the ppa for the stable package.
Copy the user and password from the above into an auth.conf.d file:
$ echo "machine private-ppa.launchpadcontent.net/crbs login lpid password x" | sudo tee /etc/apt/auth.conf.d/canonical-rbac.conf
$ sudo chmod 600 /etc/apt/auth.conf.d/canonical-rbac.conf
Configure Canonical-RBAC PPA
Import the OpenPGP key (also from ppa page):
$ wget -qO- 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x47e14cf9b38cfe770d64bab6226c2bb5a7ab3cf5' | sudo tee /etc/apt/trusted.gpg.d/canonical-rbac.asc
Add the apt source:
$ cat <<EOF | sudo tee /etc/apt/sources.list.d/canonical-rbac.list
# access to Canonical RBAC - stable packages
deb https://private-ppa.launchpadcontent.net/crbs/stable/ubuntu bionic main
deb-src https://private-ppa.launchpadcontent.net/crbs/stable/ubuntu bionic main
EOF
$ sudo apt update
Prepare Database
The postgres helper from the canonical-rbac package expects to find postgresql 10 (because the package is for bionic). We have to trick it. If you are running focal, we’ll have version 12. And jammy has 14. The correct version should be in the PGVER variable from earlier.
$ sudo ln -s $PGVER /etc/postgresql/10
Install Canonical-RBAC
Note that this also installs the canonical-rbac and candid snaps.
$ sudo apt install canonical-rbac debconf-utils -y
If installing on an HA MAAS, the PG_VIP will be a real vip and the apt install post-install script will fail. Run this line to swap localhost for the real vip:
$ sudo snap set canonical-rbac db.url="$(sudo snap get canonical-rbac db.url |
sed "s/localhost/$PG_VIP/")"
Post-Install
If the install fails the post-installation script but doesn’t give any specific reason (locale warnings can be ignored) then it may be that uwsgi has set “cheaper” higher than “workers” in /var/snap/canonical-rbac/current/conf/uwsgi.ini. This is only likely with servers with more than 50 CPUs.
$ cheaper=$(awk '/^workers/{print $3-1}' \
/var/snap/canonical-rbac/current/conf/uwsgi.ini)
$ sudo sed -E -i -e 's/^(^cheaper(-initial)? = ).*/\1 '$cheaper'/' \
/var/snap/canonical-rbac/current/conf/uwsgi.ini
$ sudo systemctl restart snap.canonical-rbac.uwsgi.service
$ sudo dpkg --configure canonical-rbac
DB Update
Skip these commands if PG_VIP is localhost. We need to update the database URLs in canonical-rbac and candid.
$ sudo debconf-get-selections | grep canonical-rbac |
sed 's/localhost/'$PG_VIP'/' | tee debconf.rbac |
sudo debconf-set-selections
$ sudo sed -i -e "s/localhost/$PG_VIP/" /var/snap/candid/current/config.yaml
$ sudo -u postgres psql rbac -c "update config set value=regexp_replace(value::text,'//[^:]*:','//$PG_VIP:')::jsonb"
DB Update
Let’s rewrite the pg_hba.conf using existing maasdb entries as a template:
$ hba_file=/etc/postgresql/$PGVER/main/pg_hba.conf
$ sudo sed -E -i -e '/(candid|rbac)/d' $hba_file
$ sudo grep maasdb $hba_file | sort -u |
sed -E -e 's/maas(db)?/candid/g' | sudo tee -a $hba_file
$ sudo grep maasdb $hba_file | sort -u |
sed -E -e 's/maas(db)?/rbac/g' | sudo tee -a $hba_file
Reload DB & Restart Candid
$ cluster=$(pg_conftool show cluster_name | awk -F\' '{print $2}')
$ sudo -u postgres pg_ctlcluster ${cluster%/*} ${cluster#*/} reload
$ sudo snap restart candid
Modify Candid Config
Edit candid config.yaml to point at the MAAS vip and to modify the admin user. Reminder: This uses MAAS_PW from somevars.sh.
$ sudo sed -E -i -e 's/(^location:[^/]*..)[^:]*(.*)/\1'$MAAS_VIP'\2/; s/(password: ).*/\1'$MAAS_PW'/; s/group1/admin/; /group2/d' /var/snap/candid/current/config.yaml
There’s also a url in admin.keys:
$ sudo sed -E -i -e 's/(.*url[^/]*..)[^:]*(.*)/\1'$MAAS_VIP'\2/' \
/var/snap/candid/current/admin.keys
$ sudo snap restart candid
Test Candid
Now candid and canonical-rbac are running on the MAAS node, backed by the same database.
We should be able to test the browser login using a candid command. This will prompt you to open a URL and authenticate using admin and the password set in config.yaml:
$ candid show -u admin
Configure MAAS
We can configure maas to talk directly to candid if we’re not using canonical-rbac.
$ sudo cp /var/snap/candid/current/admin.keys /tmp/snap-private-tmp/snap.maas/tmp/.
$ sudo maas configauth --rbac-url '' --candid-agent-file /tmp/admin.keys \
--candid-domain '' --candid-admin-group admin
Test MAAS
We now have lost access with our previous login. This will fail (print Usage):
$ maas root tags read
When we re-login, this time we will omit the api key.
$ maas login root http://$MAAS_VIP:5240/MAAS/
This will either open a web browser or present you with a URL that needs to be visited. Click “Static” and then login with “admin” and the pw in somevars.sh.
Add A User
To add/modify users, edit the config.yaml in var/snap/candid/current. Copy the lines for the admin user and make a new user called “user1”, or whatever. Add this new user to a non-admin group such as “group1”. Restart candid to for it to see the new user.
$ sudo snap restart candid
Log into MAAS WebUI
We should be able to log into MAAS using either user in our static provider configuration.a We could stop here. However, this doesn’t give us much control over what roles each kind of user has.
Configure Canonical-RBAC
Copy the admin keys to /root:
$ sudo cp /var/snap/candid/current/admin.keys /root/.
Create an agent file and tell RBAC to use it:
$ sudo canonical-rbac create-candid-agent /root/admin.keys \
--service-agent-file /root/rbac.agent
$ sudo canonical-rbac config --candid-agent-file /root/rbac.agent
The service URL will have localhost. Update it with the externally accessible host/IP:
$ sudo canonical-rbac config --service-url $RBAC_URL
Configure Canonical-RBAC
Configure the admin user as an admin in canonical-rbac. Run this command on the MAAS node:
$ sudo canonical-rbac create-admin
Now, in a web browser, visit the canonical-rbac url (from somevars.sh):
$ echo $RBAC_URL
Configure Canonical-RBAC
Click the login button. A new window will open similar to the previous auth steps.
- Log in as admin, then close that window.
- Back on the canonical-rbac page, it’ll give you the option to add a service.
- We’ll add a MAAS service called “maas01”. The name should be descriptive and unique. We will use it later when configuring maas.
- For admin, we’ll choose group and use the “admin” group. You can add a description if you wish.
- Click Add Service and the service permissions page will come up.
Configure MAAS
Now we’ll configure MAAS to use canonical-rbac. “maas01” is the service name we chose previously.
$ sudo maas configauth --rbac-url $RBAC_URL --rbac-service-name maas01
You’ll be prompted to open a URL for authentication. Login as admin. Once successful, you’ll see 'Service “maas01” registered."
Manage Roles With RBAC
We can now manage MAAS users with the WebUI.
Resources
Adding RBAC to FCE installed MAAS supports RBAC for MAAS with LDAP.
Install LXD
In the strange scenario where you don’t already have LXD installed, you can easily install it with snap:
$ sudo snap install lxd
We’ll initialize it with all the defaults:
$ lxd init --auto
LXD DNS fix
MAAS DNS listens on all interfaces. We need to ensure LXD starts up first so that LXD can properly bind dnsmasq to the lxdbr0 interface for dns and dhcp.
$ lxddir=/etc/systemd/system/snap.lxd.daemon.service.d
$ sudo mkdir -p $lxddir
$ cat <<EOF | sudo tee $lxddir/00-before-maas.conf
[Unit]
Before=snap.maas.supervisor.service
PartOf=snap.maas.supervisor.service
EOF
$ sudo systemctl daemon-reload
$ sudo systemctl restart snap.maas.supervisor snap.lxd.daemon
Point LXD to Candid
Tell LXD where to find candid:
$ lxc config set candid.api.url $CANDID_URL
Configure the public key:
$ lxc config set candid.api.key \
"$(awk '/^public/{print $2}' /var/snap/candid/current/config.yaml)"
Set LXD to listen on 8443:
$ lxc config set core.https_address :8443
Configure Client For Candid
Add a new remote to talk to the local server using candid:
$ lxc remote add candidlocal https://localhost:8443 --auth-type=candid
This will bring up the (now familiar) message to open a URL in a browser.
We can list the remotes with:
$ lxc remote list
And make the new remote the default:
$ lxc remote switch candidlocal
Now users must use candid to access our lxd over the network. Or we could restrict access to the socket (/var/snap/lxd/common/lxd/unix.socket) to force users to access the local lxd via the candid interface.
UbuntuOne
$ sudo vi /var/snap/candid/current/config.yaml
$ sudo snap restart candid
$ candid show -u vern
ERROR Get http://172.31.7.238:8081/v1/u/vern@external: permission denied
https://github.com/canonical/candid/blob/master/docs/configuration.md
Install Juju
$ sudo snap install juju --classic
Juju doesn’t like ipv6 networks with lxd.
$ lxc network set lxdbr0 ipv6.address none
$ juju bootstrap --config identity-url="$CANDID_URL" \
--config identity-public-key="$(awk '/^public/{print $2}' \
/var/snap/candid/current/config.yaml)" localhost candid-controller
$ juju add-model candid-model
$ juju grant -c candid-controller user1@example admin candid-model
$ juju change-user-password
$ juju logout
$ juju login -c candid-controller -u user1@example