15 KiB
Git GnuPG signature verification
Overview
Verify that commits in the source repository are correctly signed with one of the blessed GnuPG keys.
Note
A few words about trust
ArgoCD uses a very simple trust model for the keys you import: Once the key is imported, ArgoCD will trust it. ArgoCD does not support more complex trust models, and it is not necessary (nor possible) to sign the public keys you are going to import into ArgoCD.
Note
Compatibility notice
The GnuPG verification was first introduced in v1.7 as a project-wide constraint configured by
signatureKeys. As of vTODO, it is supported as one of the methods for source integrity verification, but it is using a different declaration format. Keys configured insignatureKeyswill continue to be supported, but they cannot be used together withsourceIntegrity. See below on how to convert the legacysignatureKeysconfiguration tosourceIntegrity.
Verification of GnuPG signatures is only supported with Git repositories. It is not possible when using Helm or OCI application sources.
The GnuPG verification requires populating the Argo CD GnuPG keyring, and configuring source integrity policies for your repositories.
Managing Argo CD GnuPG keyring
All the GnuPG keys Argo CD is going to trust must be introduced in its keyring first.
Keyring RBAC rules
The appropriate resource notation for Argo CD's RBAC implementation to allow
the managing of GnuPG keys is gpgkeys.
To allow listing of keys for a role named role:myrole, use:
p, role:myrole, gpgkeys, get, *, allow
To allow adding keys for a role named role:myrole, use:
p, role:myrole, gpgkeys, create, *, allow
And finally, to allow deletion of keys for a role named role:myrole, use:
p, role:myrole, gpgkeys, delete, *, allow
Keyring management
You can configure the GnuPG public keys that ArgoCD will use for verification of commit signatures using either the CLI, the web UI or configuring it using declarative setup.
Note
After you have imported a GnuPG key, it may take a while until the key is propagated within the cluster, even if listed as configured. If you still cannot sync to commits signed by the already imported key, please see the troubleshooting section below.
Manage public keys using the CLI
To configure GnuPG public keys using the CLI, use the argocd gpg command.
Listing all configured keys
To list all configured keys known to ArgoCD, use the argocd gpg list
sub-command:
argocd gpg list
Show information about a certain key
To get information about a specific key, use the argocd gpg get sub-command:
argocd gpg get <key-id>
Importing a key
To import a new public key to ArgoCD, use the argocd gpg add sub-command:
argocd gpg add --from <path-to-key>
The key to be imported can be either in binary or ASCII-armored format.
Removing a key from the configuration
To remove a previously configured key from the configuration, use the
argocd gpg rm sub-command:
argocd gpg rm <key-id>
Manage public keys using the Web UI
Basic key management functionality for listing, importing and removing GnuPG public keys is implemented in the Web UI. You can find the configuration module from the Settings page in the GnuPG keys module.
Please note that when you configure keys using the Web UI, the key must be imported in ASCII armored format for now.
Manage public keys in declarative setup
ArgoCD stores public keys internally in the argocd-gpg-keys-cm ConfigMap
resource, with the public GnuPG key's ID as its name and the ASCII armored
key data as string value, i.e. the entry for the GitHub's web-flow signing
key would look like follows:
4AEE18F83AFDEB23: |
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFmUaEEBCACzXTDt6ZnyaVtueZASBzgnAmK13q9Urgch+sKYeIhdymjuMQta
x15OklctmrZtqre5kwPUosG3/B2/ikuPYElcHgGPL4uL5Em6S5C/oozfkYzhwRrT
SQzvYjsE4I34To4UdE9KA97wrQjGoz2Bx72WDLyWwctD3DKQtYeHXswXXtXwKfjQ
7Fy4+Bf5IPh76dA8NJ6UtjjLIDlKqdxLW4atHe6xWFaJ+XdLUtsAroZcXBeWDCPa
buXCDscJcLJRKZVc62gOZXXtPfoHqvUPp3nuLA4YjH9bphbrMWMf810Wxz9JTd3v
yWgGqNY0zbBqeZoGv+TuExlRHT8ASGFS9SVDABEBAAG0NUdpdEh1YiAod2ViLWZs
b3cgY29tbWl0IHNpZ25pbmcpIDxub3JlcGx5QGdpdGh1Yi5jb20+iQEiBBMBCAAW
BQJZlGhBCRBK7hj4Ov3rIwIbAwIZAQAAmQEH/iATWFmi2oxlBh3wAsySNCNV4IPf
DDMeh6j80WT7cgoX7V7xqJOxrfrqPEthQ3hgHIm7b5MPQlUr2q+UPL22t/I+ESF6
9b0QWLFSMJbMSk+BXkvSjH9q8jAO0986/pShPV5DU2sMxnx4LfLfHNhTzjXKokws
+8ptJ8uhMNIDXfXuzkZHIxoXk3rNcjDN5c5X+sK8UBRH092BIJWCOfaQt7v7wig5
4Ra28pM9GbHKXVNxmdLpCFyzvyMuCmINYYADsC848QQFFwnd4EQnupo6QvhEVx1O
j7wDwvuH5dCrLuLwtwXaQh0onG4583p0LGms2Mf5F+Ick6o/4peOlBoZz48=
=Bvzs
-----END PGP PUBLIC KEY BLOCK-----
Policies for GnuPG signature verification
The GnuPG commit signature verification is configured through one or multiple Git gpg policies.
The policies are configured as illustrated:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
spec:
sourceIntegrity:
git:
policies:
- repos:
- url: "https://github.com/my-group/*"
- url: "!https://github.com/my-group/ignored.git"
gpg:
mode: "none|head|strict"
keys:
- "D56C4FCA57A46444"
The repos key contains a list of glob-style patterns matched against the URL of the source to verify.
Given strategy will be used when matched some of the positive globs, while not matched by any of the negative ones (starting with !).
Only one policy is applied per source repository, and sources not matched by any policy will not have its integrity verified.
Note that a multi-source application can have each of its source repositories validated against a different policy.
The gpg verification policy
The Git commit signature verification is an alternative to calling git verify-commit/git verify-tag with configured keyring and making sure the key ID used for the signatures is among the configured Key IDs in the source integrity policy.
If the target revision points to a commit or tags that do not satisfy those criteria, it will not be synced.
The keys key lists the set of key IDs to trust for signed commits.
If a commit in the repository is signed by an ID not specified in the list of trusted signers, the verification will fail.
The mode defines how thorough the GnuPG verification is:
Verification mode none
Verification is not performed for this strategy, and no following strategies are tried.
Note this accepts unsigned commits as well as commits with a signature that is invalid in some sense (expired, unverifiable, etc.).
Verification mode head
Verify only the commit/tag pointed to by the target revision of the source.
If the revision is an annotated tag, it is the tag's signature that is verified, not the commit's signature (i.e. the tag itself must be signed using git tag -s).
Otherwise, if target revision is a branch name, reference name (such as HEAD), or a commit SHA Argo CD verifies the commit's GnuPG signature.
Verification mode strict
Verify target revision and all its ancestors. This makes sure there is no unsigned change in the history as well. If the revision is an annotated tag, the tag's signature is verified together with the commit history, including the commit it points to.
There are situations where verifying the entire history is not practical - typically in case the history contains unsigned commits, or commits signed with keys that are no longer trusted. This happens when GnuPG verification is introduced later to the git repository, or when formerly accepted keys get removed, revoked, or rotated. While this can be addressed by re-signing with git rebase, there is a better way that does not require rewriting the Git history.
Commit seal-signing with strict mode
A sealing commit is a GnuPG signed commit that works as a "seal of approval" attesting that all its ancestor commits were either signed by a trusted key, or reviewed and trusted by the author of the sealing commit. Argo CD verifying GnuPG signatures would then progress only as far back in the history as the most recent "seal" commits in each individual ancestral branch.
In practice, a committer first reviews all commits that are not signed or signed with untrusted keys from the previous "seal commit" and creates a new, possibly empty commit with a custom Git trailer in its message. Such commits can have the following organization-level semantics:
- "From now on, we are going to GnuPG sign all commits in this repository. There is no point in verifying the unsigned ones from before."
- "I merge these changes from untrusted external contributor, and I approve of them."
- "I am removing the GnuPG key of Bob. All his previous commits are trusted, but no new ones will be. Happy retirement, Bob!"
- "I am replacing my old key with a new one. Trust my commits signed with the old key before this seal commit, but only trust my new key after this seal commit."
To create a seal commit, run git commit --signoff --gpg-sign --trailer="Argocd-gpg-seal: <justification>" and push to branch pulled by Argo CD.
Using seal commits is preferable to rewriting git history as it eliminates the room for eventual rebasing mistakes that would jeopardize either source integrity or correctness of the repository data.
Upgrade to Source Integrity Verification
To migrate from the legacy declaration to the new source verification policies, remove .spec.signatureKeys and then define desired policies in .spec.sourceIntegrity.git.policies.
To achieve the legacy Argo CD verification behavior in a project, use the following config:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
spec:
sourceIntegrity:
git:
policies:
- repos:
- url: "*" # For any repository in the project
gpg:
mode: "head" # Verify only the HEAD of the target revision
keys:
- "..." # Keys from .spec.signatureKeys
When .spec.sourceIntegrity is not defined but .spec.signatureKeys is, Argo CD will do similar conversion behind the scenes.
Though it is advised to perform the migration as source integrity config allows for greater flexibility, and .spec.signatureKeys will be a subject of removal in future releases.
Downgrade from Source Integrity Verification
At downgrade time, reintroduce .spec.signatureKeys in any AppProject, populate it with all the keys from .spec.sourceIntegrity.git.policies, and then delete the .spec.sourceIntegrity section.
Mind the legacy functionality lacks many of the new features—it will be all "head" mode for all project repositories.
As an alternative to downgrade, consult the troubleshooting section here.
Legacy signature key management (DEPRECATED)
The project-wide signature keys can be managed through UI and CLI. Note they are being replaced by the source integrity policies, so users are advised to migrate away from these.
Configuring using the CLI (DEPRECATED)
Adding a key ID to the list of allowed keys
To add a key ID to the list of allowed GnuPG keys for a project, you can use
the argocd proj add-signature-key command, i.e. the following command would
add the key ID 4AEE18F83AFDEB23 to the project named myproj:
# DEPRECATED
argocd proj add-signature-key myproj 4AEE18F83AFDEB23
Removing a key ID from the list of allowed keys
Similarly, you can remove a key ID from the list of allowed GnuPG keys for a
project using the argocd proj remove-signature-key command, i.e. to remove
the key added above from project myproj, use the command:
# DEPRECATED
argocd proj remove-signature-key myproj 4AEE18F83AFDEB23
Showing allowed key IDs for a project
To see which key IDs are allowed for a given project, you can inspect the
output of the argocd proj get command, i.e. for a project named gpg:
# DEPRECATED
$ argocd proj get gpg
Name: gpg
Description: GnuPG verification
Destinations: *,*
Repositories: *
Allowed Cluster Resources: */*
Denied Namespaced Resources: <none>
Signature keys: 4AEE18F83AFDEB23, 07E34825A909B250
Orphaned Resources: disabled
Override list of key IDs
You can also explicitly set the currently allowed keys with one or more new keys
using the argocd proj set command in combination with the --signature-keys
flag, which you can use to specify a comma separated list of allowed key IDs:
# DEPRECATED
argocd proj set myproj --signature-keys 4AEE18F83AFDEB23,07E34825A909B250
The --signature-keys flag can also be used on project creation, i.e. the
argocd proj create command.
Configure using the Web UI (DEPRECATED)
You can configure the GnuPG key IDs required for signature verification using the web UI, in the Project configuration. Navigate to the Settings page and select the Projects module, then click on the project you want to configure.
From the project's details page, click Edit and find the Required signature keys section, where you can add or remove the key IDs for signature verification. After you have modified your project, click Update to save the changes.
Troubleshooting
Disabling the feature
The GnuPG feature can be completely disabled if desired. In order to disable it,
set the environment variable ARGOCD_GPG_ENABLED to false for the pod
templates of the argocd-server, argocd-repo-server, argocd-application-controller
and argocd-applicationset-controller deployment manifests.
After the pods have been restarted, the GnuPG feature is disabled.
Inspecting GnuPG key ring
The GnuPG key ring used for signature verification is maintained within the
pods of argocd-repo-server. The keys in the keyring are synchronized to the
configuration stored in the argocd-gpg-keys-cm ConfigMap resource, which is
volume-mounted to the argocd-repo-server pods.
Note
The GnuPG key ring in the pods is transient and gets recreated from the configuration on each restart of the pods. You should never add or remove keys manually to the key ring in the pod, because your changes will be lost. Also, any of the private keys found in the key ring are transient and will be regenerated upon each restart. The private key is only used to build the trust DB for the running pod.
To check whether the keys are actually in sync, you can kubectl exec into the
repository server's pods and inspect the key ring, which is located at path
/app/config/gpg/keys
$ kubectl exec -it argocd-repo-server-7d6bdfdf6d-hzqkg bash
argocd@argocd-repo-server-7d6bdfdf6d-hzqkg:~$ GNUPGHOME=/app/config/gpg/keys gpg --list-keys
/app/config/gpg/keys/pubring.kbx
--------------------------------
pub rsa2048 2020-06-15 [SC] [expires: 2020-12-12]
D48F075D818A813C436914BC9324F0D2144753B1
uid [ultimate] Anon Ymous (ArgoCD key signing key) <noreply@argoproj.io>
pub rsa2048 2017-08-16 [SC]
5DE3E0509C47EA3CF04A42D34AEE18F83AFDEB23
uid [ultimate] GitHub (web-flow commit signing) <noreply@github.com>
argocd@argocd-repo-server-7d6bdfdf6d-hzqkg:~$
If the key ring stays out of sync with your configuration after you have added
or removed keys for a longer period of time, you might want to restart your
argocd-repo-server pods. If such a problem persists, please consider raising
a bug report.