comin is a pull mode NixOS deployment tool: it polls Git repositories and deploys new commits. It can now verify these commits are signed, to exclude attacks on the remote Git repository.
To automate the deployment of your NixOS machines with comin, you only need to add 3 lines in your configuration. It is really easy to use because you don’t need to configure a CICD nor store secrets. However, it requires you to trust the remote Git repository. When the Git repository is compromised, the attacker controls what is deployed on your machines.
To address this problem, comin can now verify Git commit signatures before deploying a commit.
Configure comin to verify Git commit signature Link to heading
-
Export your GPG public key with
gpg --armor --export alice@cyb.org > ./public-key.gpg
-
Provide to comin a list of GPG public keys (via the attribute
gpgPublicKeyPaths
)services.comin = { enable = true; gpgPublicKeyPaths = [ ./public-key.gpg ]; remotes = [{ name = "origin"; url = "https://git.com/your/infra.git"; }];
-
Create a signed commit with
git commit -a -S -m 'Signed commit'
and push it to your remote.
And that’s all.
When comin fetches a commit, it now checks the commit has been signed by one of these keys. If the fetched commit is not signed by at least one of these keys, comin refuses to deploy this commit.
Fast-forward only to avoid hard reset attacks Link to heading
Only checking the commit signature is not enough because an attacker could reset the repository to a previously signed commit (for instance, an older commit exposed to a CVE).
To avoid this attack, comin ensures the main
branch repository has
not been pushed forced to a previous commit: comin stores the last
commit ID of the main
branch and verifies this commit is a parent of
all new fetched commits. If it is not, comin doesn’t checkout such kind
of commits.
Testing branches Link to heading
We have seen comin refuses to fetch from the main
branch if it has
been hard reset. For the testing branch, this constraint has been
relaxed. comin only ensures the testing
branch is on top of the
main
branch. An attacker could hard reset the testing
branch, but
only to a commit having the current main
commit as parent which
limits the risk.
If you consider this risk is too important, you can still never push
commits to testing
branches or explicitly disable the testing
branch feature.
Future works Link to heading
It would be nice to be able to configure signature checks per remotes and/or per branches.
Regarding the security model, there is still an issue when you
bootstrap comin. The first time comin runs on a machine, it doesn’t
know the latest main
commit. So, it could fetch an already corrupted
remote. To avoid this issue, it could be possible to add an option to specify the parent commit
ID of the first fetched commit.
Conclusion Link to heading
comin can now ensure only authorized people are allowed to deploy configurations to NixOS machines. These people don’t need any access to the machines (no SSH required) and comin doesn’t rely on a secret (a public key is not a secret). I think these properties are pretty valuable for infrastructures managed by communities, because several people are publicly allowed to deploy configurations, without having an SSH access to the machines.