Initial implementation
Implement a replacement for the existing pw-manager script. If called as the existing one is called, the behaviour is the same: commands are passed over stdin to a remote command started via SSH and the exit status of the remote command is teleported back.
The "unlock-account" and "lock-account" commands have not been implemented because the existing Raven implementation does not implement them either.
Using some trickery we also package the command as a static binary suitable for direct deployment on to the VM. These are uploaded as CI artefacts and are also directly linked to in the Merge Request itself as you can see in the following screnshot:
The static binary itself is around 12MiB which is pretty compact given it packages everything we need along with a complete Python interpreter. The static binary also encodes its git commit sha if built outside of main:
rjw57@password-test:~> ./pw-manager --version
0c06ed302086305aef39cedde7d2f1627f28ac0d
Testing on password-test
implies that the SSH part is functional:
rjw57@password-test:~> cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+l/+lVNB2kkvjoSN6ANoBIr6RKAWiueVr2FgtJDNZlJBrJTCtI2FBW+BPzaHKZZ1gA6y+0qM4x71eiT+ZqMG8COXU9V58qLof4bgHUq5i/3nXVfjdh+PDJN0eDBL/uHlEiv720K0agGnMnr4YDmTQRGOPBL7pKRs02hz5kHbKfcFBJEJaM9jc5pt2N3v/7VX3JCUqx3sMsWeHjI6AAkBC1wc3pBPGBbIXhtkm3JX33ScjdmCwsnMLI6UW2KLGJ53TPGKIUYAXCIFq2z+ICrdphIwWanZ+A+VUsSZ9/LFdi+PrJcHDjLXIa2SuX5Ae2OHdepog1A6ZX8fAb6TgVlYh rjw57@password-test
rjw57@password-test:~> tail -n 1 ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+l/+lVNB2kkvjoSN6ANoBIr6RKAWiueVr2FgtJDNZlJBrJTCtI2FBW+BPzaHKZZ1gA6y+0qM4x71eiT+ZqMG8COXU9V58qLof4bgHUq5i/3nXVfjdh+PDJN0eDBL/uHlEiv720K0agGnMnr4YDmTQRGOPBL7pKRs02hz5kHbKfcFBJEJaM9jc5pt2N3v/7VX3JCUqx3sMsWeHjI6AAkBC1wc3pBPGBbIXhtkm3JX33ScjdmCwsnMLI6UW2KLGJ53TPGKIUYAXCIFq2z+ICrdphIwWanZ+A+VUsSZ9/LFdi+PrJcHDjLXIa2SuX5Ae2OHdepog1A6ZX8fAb6TgVlYh rjw57@password-test
rjw57@password-test:~> ls -lh pw-manager
-rwxr-xr-x 1 rjw57 rjw57 12M Nov 18 08:14 pw-manager
rjw57@password-test:~> echo "input" | ./pw-manager rjw57 localhost 10 wc
1 1 6
rjw57@password-test:~> echo "input" | ./pw-manager rjw57 localhost 10 id; echo $?
uid=53956(rjw57) gid=53956(rjw57) groups=53956(rjw57),14(uucp),16(dialout),17(audio),33(video)
0
rjw57@password-test:~> echo "input" | ./pw-manager rjw57 localhost 10 no-such-command; echo $?
bash: no-such-command: command not found
127
If the username is the magic value "__google_id_token" then we instead make use of the "new style" REST API. We still pass commands in on stdin but they are now parsed locally by pw-manager and enacted directly using the API.
With some manually created credentials for password-manager@raven-legacy-devel-27608283.iam.gserviceaccount.com
(added to 1password), the API side is also working:
rjw57@password-test:~> ls -lh $GOOGLE_APPLICATION_CREDENTIALS
-rw------- 1 rjw57 rjw57 2.4K Nov 18 08:21 /home/rjw57/credentials.json
rjw57@password-test:~> cat passwords.env
PASSWORDS_API_AUDIENCE=274492657148-k56h93uf5sghuuh80i2p9v6tdtoi1cbl.apps.googleusercontent.com
rjw57@password-test:~> echo "get-salt $(echo -n test0001 | base64)" | \
./pw-manager __google_id_token https://admin-api.devel.raven-legacy.gcp.uis.cam.ac.uk/ \
10 this-argument-does-not-matter; echo $?
$1$4bsCYJMV
0
rjw57@password-test:~> echo "get-salt $(echo -n jack-the-ripper | base64)" | \
./pw-manager __google_id_token https://admin-api.devel.raven-legacy.gcp.uis.cam.ac.uk/ \
10 this-argument-does-not-matter; echo $?
Error running command: No such user: jack-the-ripper
204
See the README for details on this.
Note that PASSWORDS_...
are not secret but to avoid cluttering up the repo with deployment-specific details, the appropriate values for staging, development and production are available in 1password.
Opening for review early to get some early testing on a) the re-implementation of the SSH API method and b) the REST API authentication.
Part of https://gitlab.developers.cam.ac.uk/uis/devops/raven/passwords/passwords/-/issues/23. This does not close the issue because it only implements the wrapper, it does not deploy it.