From 43e13352676bd29f0ee0f663aa3064f604ef355a Mon Sep 17 00:00:00 2001 From: Dustin Lactin Date: Sat, 11 May 2024 21:14:20 -0600 Subject: [PATCH 1/3] Added support for ssh signed commits and completed gpg signed commit work Signed-off-by: Dustin Lactin --- .github/actions/spelling/expect.txt | 5 ++ cmd/main.go | 2 + cmd/run.go | 4 ++ docs/basics/update-methods.md | 49 ++++++++++++++++++- ext/git/client.go | 1 + ext/git/mocks/Client.go | 14 ++++++ ext/git/writer.go | 39 ++++++++++++++- .../argocd-image-updater-deployment.yaml | 24 +++++++++ manifests/install.yaml | 24 +++++++++ pkg/argocd/git.go | 14 ++++++ pkg/argocd/update.go | 8 +++ 11 files changed, 181 insertions(+), 3 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 642a1bc4..d0867389 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -2,6 +2,9 @@ aeece Artifactory applicationid +atlassian +Bitbucket +bitbucketserver bacd CVE credref @@ -11,7 +14,9 @@ eec fbd ffb gitlab +GPG helmvalues +html installationid jfrog mep diff --git a/cmd/main.go b/cmd/main.go index de6f0c69..2b008d09 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -45,6 +45,8 @@ type ImageUpdaterConfig struct { GitCommitUser string GitCommitMail string GitCommitMessage *template.Template + GitCommitSigningKey string + GitCommitSignOff bool DisableKubeEvents bool GitCreds git.CredsStore } diff --git a/cmd/run.go b/cmd/run.go index bcc0e1fe..30eae397 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -240,6 +240,8 @@ func newRunCommand() *cobra.Command { runCmd.Flags().BoolVar(&warmUpCache, "warmup-cache", true, "whether to perform a cache warm-up on startup") runCmd.Flags().StringVar(&cfg.GitCommitUser, "git-commit-user", env.GetStringVal("GIT_COMMIT_USER", "argocd-image-updater"), "Username to use for Git commits") runCmd.Flags().StringVar(&cfg.GitCommitMail, "git-commit-email", env.GetStringVal("GIT_COMMIT_EMAIL", "noreply@argoproj.io"), "E-Mail address to use for Git commits") + runCmd.Flags().StringVar(&cfg.GitCommitSigningKey, "git-commit-signing-key", env.GetStringVal("GIT_COMMIT_SIGNING_KEY", ""), "GnuPG key ID or path to Public SSH Key used to sign the commits") + runCmd.Flags().BoolVar(&cfg.GitCommitSignOff, "git-commit-sign-off", env.GetBoolVal("GIT_COMMIT_SIGN_OFF", false), "Whether to sign-off git commits") runCmd.Flags().StringVar(&commitMessagePath, "git-commit-message-path", defaultCommitTemplatePath, "Path to a template to use for Git commit messages") runCmd.Flags().BoolVar(&cfg.DisableKubeEvents, "disable-kube-events", env.GetBoolVal("IMAGE_UPDATER_KUBE_EVENTS", false), "Disable kubernetes events") @@ -327,6 +329,8 @@ func runImageUpdater(cfg *ImageUpdaterConfig, warmUp bool) (argocd.ImageUpdaterR GitCommitUser: cfg.GitCommitUser, GitCommitEmail: cfg.GitCommitMail, GitCommitMessage: cfg.GitCommitMessage, + GitCommitSigningKey: cfg.GitCommitSigningKey, + GitCommitSignOff: cfg.GitCommitSignOff, DisableKubeEvents: cfg.DisableKubeEvents, GitCreds: cfg.GitCreds, } diff --git a/docs/basics/update-methods.md b/docs/basics/update-methods.md index 404b5aa4..1f3f0a76 100644 --- a/docs/basics/update-methods.md +++ b/docs/basics/update-methods.md @@ -153,7 +153,8 @@ format. To create such a secret from an existing private key, you can use ```bash kubectl -n argocd-image-updater create secret generic git-creds \ - --from-file=sshPrivateKey=~/.ssh/id_rsa + --from-file=sshPrivateKey=~/.ssh/id_rsa \ + --from-file=sshPublicKey=~/.ssh/id_rsa.pub \ ``` ### Specifying a repository when using a Helm repository in repoURL @@ -247,6 +248,52 @@ as the author. You can override the author using the `git.user` and `git.email` in the `argocd-image-updater-config` ConfigMap. +### Enabling commit signature verification using an SSH or GPG key +Commit signing requires the repository be accessed using HTTPS or SSH with a user account. +Repositories accessed using a GitHub App can not be verified when using the git command line at this time. + +Each Git commit associated with an author's name and email address can be signed via a public SSH key or GPG key. +Commit signing requires a bot account with a GPG or SSH key and the username and email address configured to match the bot account. + +Your preferred signing key must be associated with your bot account. See provider documentation for further details: +* [GitHub](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) +* [GitLab](https://docs.gitlab.com/ee/user/project/repository/signed_commits/) +* [Bitbucket](https://confluence.atlassian.com/bitbucketserver/controlling-access-to-code-776639770.html) + +Commit Sign Off can be enabled by setting `git.commit-sign-off: "true"` + +**SSH:** + +Both private and public keys must be mounted and accessible on the `argocd-image-updater` pod. + +Set `git.commit-signing-key` `argocd-image-updater-config` ConfigMap to the path of your public key: + +```yaml +data: + git.commit-sign-off: "true" + git.commit-signing-key: /app/.ssh/id_rsa.pub +``` + +The matching private key must be available in the same location. + +Create a new SSH secret or add the public key to your existing SSH secret: +```bash +kubectl -n argocd-image-updater create secret generic ssh-git-creds \ + --from-file=sshPrivateKey=~/.ssh/id_rsa \ + --from-file=sshPublicKey=~/.ssh/id_rsa.pub +``` + +**GPG:** + +The GPG private key must be installed and available in the `argocd-image-updater` pod. +Set `git.commit-signing-key` in the `argocd-image-updater-config` ConfigMap to the GPG key ID you want to use: + +```yaml +data: + git.commit-sign-off: "true" + git.commit-signing-key: 3AA5C34371567BD2 +``` + ### Changing the Git commit message You can change the default commit message used by Argo CD Image Updater to some diff --git a/ext/git/client.go b/ext/git/client.go index ac9dc105..5fed9d3d 100644 --- a/ext/git/client.go +++ b/ext/git/client.go @@ -82,6 +82,7 @@ type Client interface { Add(path string) error SymRefToBranch(symRef string) (string, error) Config(username string, email string) error + SigningConfig(signingkey string) error } type EventHandlers struct { diff --git a/ext/git/mocks/Client.go b/ext/git/mocks/Client.go index 63252281..87bd3b46 100644 --- a/ext/git/mocks/Client.go +++ b/ext/git/mocks/Client.go @@ -160,6 +160,20 @@ func (_m *Client) Config(username string, email string) error { return r0 } +// SigningConfig provides a mock function with given fields: signingkey +func (_m *Client) SigningConfig(signingkey string) error { + ret := _m.Called(signingkey) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(signingkey) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // Fetch provides a mock function with given fields: revision func (_m *Client) Fetch(revision string) error { ret := _m.Called(revision) diff --git a/ext/git/writer.go b/ext/git/writer.go index 7b84ff92..19a663a6 100644 --- a/ext/git/writer.go +++ b/ext/git/writer.go @@ -3,6 +3,7 @@ package git import ( "fmt" "os/exec" + "regexp" "strings" "github.com/argoproj-labs/argocd-image-updater/pkg/log" @@ -14,7 +15,7 @@ type CommitOptions struct { CommitMessageText string // CommitMessagePath holds the path to a file to be used for the commit message (-F option) CommitMessagePath string - // SigningKey holds a GnuPG key ID used to sign the commit with (-S option) + // SigningKey holds a GnuPG key ID or path to Public SSH Key used to sign the commit with (-S option) SigningKey string // SignOff specifies whether to sign-off a commit (-s option) SignOff bool @@ -33,7 +34,16 @@ func (m *nativeGitClient) Commit(pathSpec string, opts *CommitOptions) error { args = append(args, "-a") } if opts.SigningKey != "" { - args = append(args, "-S", opts.SigningKey) + // Check if SiginingKey is a GPG key or Public SSH Key + keyCheck, err := regexp.MatchString(".*pub$", opts.SigningKey) + if err != nil { + return fmt.Errorf("could not validate Signing Key as GPG or Public SSH Key: %v", err) + } + if keyCheck { + args = append(args, "-S") + } else { + args = append(args, "-S", opts.SigningKey) + } } if opts.SignOff { args = append(args, "-s") @@ -147,3 +157,28 @@ func (m *nativeGitClient) runCredentialedCmdWithOutput(args ...string) (string, cmd.Env = append(cmd.Env, environ...) return m.runCmdOutput(cmd, runOpts{}) } + +// SigningConfig configures commit signing for the repository +func (m *nativeGitClient) SigningConfig(signingkey string) error { + // Check if SiginingKey is a GPG key or Public SSH Key + keyCheck, err := regexp.MatchString(".*pub$", signingkey) + if err != nil { + return fmt.Errorf("could not validate Signing Key as GPG or Public SSH Key: %v", err) + } + if keyCheck { + // Setting the GPG format to ssh + log.Warnf("Setting GPG Format to SSH") + _, err = m.runCmd("config", "gpg.format", "ssh") + if err != nil { + return fmt.Errorf("could not set gpg format to ssh: %v", err) + } + // Setting Public SSH Key as our signing key + // SSH Keys can not currently be set via cli flag + _, err = m.runCmd("config", "user.signingkey", signingkey) + if err != nil { + return fmt.Errorf("could not set git signing key: %v", err) + } + } + + return nil +} diff --git a/manifests/base/deployment/argocd-image-updater-deployment.yaml b/manifests/base/deployment/argocd-image-updater-deployment.yaml index 5682ed78..4febed29 100644 --- a/manifests/base/deployment/argocd-image-updater-deployment.yaml +++ b/manifests/base/deployment/argocd-image-updater-deployment.yaml @@ -77,6 +77,18 @@ spec: name: argocd-image-updater-config key: git.email optional: true + - name: GIT_COMMIT_SIGNING_KEY + valueFrom: + configMapKeyRef: + key: git.commit-signing-key + name: argocd-image-updater-config + optional: true + - name: GIT_COMMIT_SIGN_OFF + valueFrom: + configMapKeyRef: + key: git.commit-sign-off + name: argocd-image-updater-config + optional: true - name: IMAGE_UPDATER_KUBE_EVENTS valueFrom: configMapKeyRef: @@ -116,6 +128,14 @@ spec: name: ssh-config - mountPath: /tmp name: tmp + - name: ssh-signing-key + mountPath: /app/.ssh/id_rsa + readOnly: true + subPath: sshPrivateKey + - name: ssh-signing-key + mountPath: /app/.ssh/id_rsa.pub + readOnly: true + subPath: sshPublicKey serviceAccountName: argocd-image-updater volumes: - configMap: @@ -135,5 +155,9 @@ spec: name: argocd-image-updater-ssh-config optional: true name: ssh-config + - name: ssh-signing-key + secret: + secretName: ssh-git-creds + optional: true - emptyDir: {} name: tmp diff --git a/manifests/install.yaml b/manifests/install.yaml index b65b12bd..47b9e01f 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -158,6 +158,18 @@ spec: key: git.email name: argocd-image-updater-config optional: true + - name: GIT_COMMIT_SIGNING_KEY + valueFrom: + configMapKeyRef: + key: git.commit-signing-key + name: argocd-image-updater-config + optional: true + - name: GIT_COMMIT_SIGN_OFF + valueFrom: + configMapKeyRef: + key: git.commit-sign-off + name: argocd-image-updater-config + optional: true - name: IMAGE_UPDATER_KUBE_EVENTS valueFrom: configMapKeyRef: @@ -199,6 +211,14 @@ spec: name: ssh-config - mountPath: /tmp name: tmp + - mountPath: /app/.ssh/id_rsa + name: ssh-signing-key + readOnly: true + subPath: sshPrivateKey + - mountPath: /app/.ssh/id_rsa.pub + name: ssh-signing-key + readOnly: true + subPath: sshPublicKey serviceAccountName: argocd-image-updater volumes: - configMap: @@ -218,5 +238,9 @@ spec: name: argocd-image-updater-ssh-config optional: true name: ssh-config + - name: ssh-signing-key + optional: true + secret: + secretName: ssh-git-creds - emptyDir: {} name: tmp diff --git a/pkg/argocd/git.go b/pkg/argocd/git.go index 71a610a5..4ced14e6 100644 --- a/pkg/argocd/git.go +++ b/pkg/argocd/git.go @@ -169,6 +169,14 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, changeLis } } + // Set commit signing configuration + if wbc.GitCommitSigningKey != "" { + err = gitC.SigningConfig(wbc.GitCommitSigningKey) + if err != nil { + return err + } + } + // The branch to checkout is either a configured branch in the write-back // config, or taken from the application spec's targetRevision. If the // target revision is set to the special value HEAD, or is the empty @@ -234,6 +242,12 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, changeLis defer os.Remove(cm.Name()) } + if wbc.GitCommitSigningKey != "" { + commitOpts.SigningKey = wbc.GitCommitSigningKey + } + + commitOpts.SignOff = wbc.GitCommitSignOff + err = gitC.Commit("", commitOpts) if err != nil { return err diff --git a/pkg/argocd/update.go b/pkg/argocd/update.go index 98592d8b..43f5c7d6 100644 --- a/pkg/argocd/update.go +++ b/pkg/argocd/update.go @@ -44,6 +44,8 @@ type UpdateConfiguration struct { GitCommitUser string GitCommitEmail string GitCommitMessage *template.Template + GitCommitSigningKey string + GitCommitSignOff bool DisableKubeEvents bool IgnorePlatforms bool GitCreds git.CredsStore @@ -70,6 +72,8 @@ type WriteBackConfig struct { GitCommitUser string GitCommitEmail string GitCommitMessage string + GitCommitSigningKey string + GitCommitSignOff bool KustomizeBase string Target string GitRepo string @@ -330,6 +334,10 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat if len(changeList) > 0 && updateConf.GitCommitMessage != nil { wbc.GitCommitMessage = TemplateCommitMessage(updateConf.GitCommitMessage, updateConf.UpdateApp.Application.Name, changeList) } + if updateConf.GitCommitSigningKey != "" { + wbc.GitCommitSigningKey = updateConf.GitCommitSigningKey + } + wbc.GitCommitSignOff = updateConf.GitCommitSignOff } if needUpdate { From 4ce19f280322d85667c66ae879d4c0c2cbbe1575 Mon Sep 17 00:00:00 2001 From: Dustin Lactin Date: Mon, 3 Jun 2024 15:10:29 -0600 Subject: [PATCH 2/3] Removed public key requirement, removed SigningConfig function, updated commit function and documentation Signed-off-by: Dustin Lactin --- .github/actions/spelling/expect.txt | 1 + cmd/main.go | 43 ++++++++------- cmd/run.go | 28 +++++----- docs/basics/update-methods.md | 35 +++++++----- ext/git/client.go | 1 - ext/git/writer.go | 51 ++++------------- .../argocd-image-updater-deployment.yaml | 10 ++-- manifests/install.yaml | 10 ++-- pkg/argocd/git.go | 9 +-- pkg/argocd/update.go | 55 ++++++++++--------- 10 files changed, 110 insertions(+), 133 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index d0867389..66286858 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -21,6 +21,7 @@ installationid jfrog mep myregistry +openpgp PRIVATEKEYDATA repocreds rollbacked diff --git a/cmd/main.go b/cmd/main.go index 2b008d09..81eed761 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -28,27 +28,28 @@ const applicationsAPIKindArgoCD = "argocd" // ImageUpdaterConfig contains global configuration and required runtime data type ImageUpdaterConfig struct { - ApplicationsAPIKind string - ClientOpts argocd.ClientOptions - ArgocdNamespace string - DryRun bool - CheckInterval time.Duration - ArgoClient argocd.ArgoCD - LogLevel string - KubeClient *kube.KubernetesClient - MaxConcurrency int - HealthPort int - MetricsPort int - RegistriesConf string - AppNamePatterns []string - AppLabel string - GitCommitUser string - GitCommitMail string - GitCommitMessage *template.Template - GitCommitSigningKey string - GitCommitSignOff bool - DisableKubeEvents bool - GitCreds git.CredsStore + ApplicationsAPIKind string + ClientOpts argocd.ClientOptions + ArgocdNamespace string + DryRun bool + CheckInterval time.Duration + ArgoClient argocd.ArgoCD + LogLevel string + KubeClient *kube.KubernetesClient + MaxConcurrency int + HealthPort int + MetricsPort int + RegistriesConf string + AppNamePatterns []string + AppLabel string + GitCommitUser string + GitCommitMail string + GitCommitMessage *template.Template + GitCommitSigningKey string + GitCommitSigningMethod string + GitCommitSignOff bool + DisableKubeEvents bool + GitCreds git.CredsStore } // newRootCommand implements the root command of argocd-image-updater diff --git a/cmd/run.go b/cmd/run.go index 30eae397..751c29c9 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -240,7 +240,8 @@ func newRunCommand() *cobra.Command { runCmd.Flags().BoolVar(&warmUpCache, "warmup-cache", true, "whether to perform a cache warm-up on startup") runCmd.Flags().StringVar(&cfg.GitCommitUser, "git-commit-user", env.GetStringVal("GIT_COMMIT_USER", "argocd-image-updater"), "Username to use for Git commits") runCmd.Flags().StringVar(&cfg.GitCommitMail, "git-commit-email", env.GetStringVal("GIT_COMMIT_EMAIL", "noreply@argoproj.io"), "E-Mail address to use for Git commits") - runCmd.Flags().StringVar(&cfg.GitCommitSigningKey, "git-commit-signing-key", env.GetStringVal("GIT_COMMIT_SIGNING_KEY", ""), "GnuPG key ID or path to Public SSH Key used to sign the commits") + runCmd.Flags().StringVar(&cfg.GitCommitSigningKey, "git-commit-signing-key", env.GetStringVal("GIT_COMMIT_SIGNING_KEY", ""), "GnuPG key ID or path to Private SSH Key used to sign the commits") + runCmd.Flags().StringVar(&cfg.GitCommitSigningMethod, "git-commit-signing-method", env.GetStringVal("GIT_COMMIT_SIGNING_METHOD", "openpgp"), "Method used to sign Git commits ('openpgp' or 'ssh')") runCmd.Flags().BoolVar(&cfg.GitCommitSignOff, "git-commit-sign-off", env.GetBoolVal("GIT_COMMIT_SIGN_OFF", false), "Whether to sign-off git commits") runCmd.Flags().StringVar(&commitMessagePath, "git-commit-message-path", defaultCommitTemplatePath, "Path to a template to use for Git commit messages") runCmd.Flags().BoolVar(&cfg.DisableKubeEvents, "disable-kube-events", env.GetBoolVal("IMAGE_UPDATER_KUBE_EVENTS", false), "Disable kubernetes events") @@ -321,18 +322,19 @@ func runImageUpdater(cfg *ImageUpdaterConfig, warmUp bool) (argocd.ImageUpdaterR defer sem.Release(1) log.Debugf("Processing application %s", app) upconf := &argocd.UpdateConfiguration{ - NewRegFN: registry.NewClient, - ArgoClient: cfg.ArgoClient, - KubeClient: cfg.KubeClient, - UpdateApp: &curApplication, - DryRun: dryRun, - GitCommitUser: cfg.GitCommitUser, - GitCommitEmail: cfg.GitCommitMail, - GitCommitMessage: cfg.GitCommitMessage, - GitCommitSigningKey: cfg.GitCommitSigningKey, - GitCommitSignOff: cfg.GitCommitSignOff, - DisableKubeEvents: cfg.DisableKubeEvents, - GitCreds: cfg.GitCreds, + NewRegFN: registry.NewClient, + ArgoClient: cfg.ArgoClient, + KubeClient: cfg.KubeClient, + UpdateApp: &curApplication, + DryRun: dryRun, + GitCommitUser: cfg.GitCommitUser, + GitCommitEmail: cfg.GitCommitMail, + GitCommitMessage: cfg.GitCommitMessage, + GitCommitSigningKey: cfg.GitCommitSigningKey, + GitCommitSigningMethod: cfg.GitCommitSigningMethod, + GitCommitSignOff: cfg.GitCommitSignOff, + DisableKubeEvents: cfg.DisableKubeEvents, + GitCreds: cfg.GitCreds, } res := argocd.UpdateApplication(upconf, syncState) result.NumApplicationsProcessed += 1 diff --git a/docs/basics/update-methods.md b/docs/basics/update-methods.md index 1f3f0a76..73d82bf7 100644 --- a/docs/basics/update-methods.md +++ b/docs/basics/update-methods.md @@ -153,8 +153,7 @@ format. To create such a secret from an existing private key, you can use ```bash kubectl -n argocd-image-updater create secret generic git-creds \ - --from-file=sshPrivateKey=~/.ssh/id_rsa \ - --from-file=sshPublicKey=~/.ssh/id_rsa.pub \ + --from-file=sshPrivateKey=~/.ssh/id_rsa ``` ### Specifying a repository when using a Helm repository in repoURL @@ -248,44 +247,48 @@ as the author. You can override the author using the `git.user` and `git.email` in the `argocd-image-updater-config` ConfigMap. -### Enabling commit signature verification using an SSH or GPG key -Commit signing requires the repository be accessed using HTTPS or SSH with a user account. +## Enabling commit signature signing using an SSH or GPG key + +### 1. SCM branch protection rules require signed commits +Commit signing for SCM branch protection rules require the repository be accessed using HTTPS or SSH with a user account. Repositories accessed using a GitHub App can not be verified when using the git command line at this time. -Each Git commit associated with an author's name and email address can be signed via a public SSH key or GPG key. +Each Git commit associated with an author's name and email address can be signed via a private SSH key or GPG key. + Commit signing requires a bot account with a GPG or SSH key and the username and email address configured to match the bot account. -Your preferred signing key must be associated with your bot account. See provider documentation for further details: +Your preferred signing key must be associated with your bot account. See SCM provider documentation for further details: * [GitHub](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) * [GitLab](https://docs.gitlab.com/ee/user/project/repository/signed_commits/) * [Bitbucket](https://confluence.atlassian.com/bitbucketserver/controlling-access-to-code-776639770.html) -Commit Sign Off can be enabled by setting `git.commit-sign-off: "true"` +### 2. Signing commits for future use with ArgoCD Source Verification Policies +Commits can also be signed for use with source verification. +In this case signing keys do not need to be associated with an SCM user account. **SSH:** -Both private and public keys must be mounted and accessible on the `argocd-image-updater` pod. +The private key must be mounted and accessible on the `argocd-image-updater` pod. -Set `git.commit-signing-key` `argocd-image-updater-config` ConfigMap to the path of your public key: +Set `git.commit-signing-key` `argocd-image-updater-config` ConfigMap to the path of your private key: ```yaml data: git.commit-sign-off: "true" - git.commit-signing-key: /app/.ssh/id_rsa.pub + git.commit-signing-key: /app/.ssh/id_rsa + git.commit-signing-method: "ssh" ``` -The matching private key must be available in the same location. - -Create a new SSH secret or add the public key to your existing SSH secret: +Create a new SSH secret or use your existing SSH secret: ```bash kubectl -n argocd-image-updater create secret generic ssh-git-creds \ - --from-file=sshPrivateKey=~/.ssh/id_rsa \ - --from-file=sshPublicKey=~/.ssh/id_rsa.pub + --from-file=sshPrivateKey=~/.ssh/id_rsa ``` **GPG:** The GPG private key must be installed and available in the `argocd-image-updater` pod. +The `git.commit-signing-method` defaults to `openpgp`. Set `git.commit-signing-key` in the `argocd-image-updater-config` ConfigMap to the GPG key ID you want to use: ```yaml @@ -294,6 +297,8 @@ data: git.commit-signing-key: 3AA5C34371567BD2 ``` +#### Commit Sign Off can be enabled by setting `git.commit-sign-off: "true"` + ### Changing the Git commit message You can change the default commit message used by Argo CD Image Updater to some diff --git a/ext/git/client.go b/ext/git/client.go index 5fed9d3d..ac9dc105 100644 --- a/ext/git/client.go +++ b/ext/git/client.go @@ -82,7 +82,6 @@ type Client interface { Add(path string) error SymRefToBranch(symRef string) (string, error) Config(username string, email string) error - SigningConfig(signingkey string) error } type EventHandlers struct { diff --git a/ext/git/writer.go b/ext/git/writer.go index 19a663a6..94535aec 100644 --- a/ext/git/writer.go +++ b/ext/git/writer.go @@ -3,7 +3,6 @@ package git import ( "fmt" "os/exec" - "regexp" "strings" "github.com/argoproj-labs/argocd-image-updater/pkg/log" @@ -15,8 +14,10 @@ type CommitOptions struct { CommitMessageText string // CommitMessagePath holds the path to a file to be used for the commit message (-F option) CommitMessagePath string - // SigningKey holds a GnuPG key ID or path to Public SSH Key used to sign the commit with (-S option) + // SigningKey holds a GnuPG key ID or path to a Private SSH Key used to sign the commit with (-S option) SigningKey string + // SigningMethod holds the signing method used to sign commits. (git -c gpg.format=ssh option) + SigningMethod string // SignOff specifies whether to sign-off a commit (-s option) SignOff bool } @@ -26,25 +27,18 @@ type CommitOptions struct { // changes will be commited. If message is not the empty string, it will be // used as the commit message, otherwise a default commit message will be used. // If signingKey is not the empty string, commit will be signed with the given -// GPG key. +// GPG or SSH key. func (m *nativeGitClient) Commit(pathSpec string, opts *CommitOptions) error { defaultCommitMsg := "Update parameters" - args := []string{"commit"} + // Git configuration + config := "gpg.format=" + opts.SigningMethod + args := []string{"-c", config, "commit"} if pathSpec == "" || pathSpec == "*" { args = append(args, "-a") } - if opts.SigningKey != "" { - // Check if SiginingKey is a GPG key or Public SSH Key - keyCheck, err := regexp.MatchString(".*pub$", opts.SigningKey) - if err != nil { - return fmt.Errorf("could not validate Signing Key as GPG or Public SSH Key: %v", err) - } - if keyCheck { - args = append(args, "-S") - } else { - args = append(args, "-S", opts.SigningKey) - } - } + // Commit fails with a space between -S flag and path to SSH key + // -S/user/test/.ssh/signingKey or -SAAAAAAAA... + args = append(args, fmt.Sprintf("-S%s", opts.SigningKey)) if opts.SignOff { args = append(args, "-s") } @@ -157,28 +151,3 @@ func (m *nativeGitClient) runCredentialedCmdWithOutput(args ...string) (string, cmd.Env = append(cmd.Env, environ...) return m.runCmdOutput(cmd, runOpts{}) } - -// SigningConfig configures commit signing for the repository -func (m *nativeGitClient) SigningConfig(signingkey string) error { - // Check if SiginingKey is a GPG key or Public SSH Key - keyCheck, err := regexp.MatchString(".*pub$", signingkey) - if err != nil { - return fmt.Errorf("could not validate Signing Key as GPG or Public SSH Key: %v", err) - } - if keyCheck { - // Setting the GPG format to ssh - log.Warnf("Setting GPG Format to SSH") - _, err = m.runCmd("config", "gpg.format", "ssh") - if err != nil { - return fmt.Errorf("could not set gpg format to ssh: %v", err) - } - // Setting Public SSH Key as our signing key - // SSH Keys can not currently be set via cli flag - _, err = m.runCmd("config", "user.signingkey", signingkey) - if err != nil { - return fmt.Errorf("could not set git signing key: %v", err) - } - } - - return nil -} diff --git a/manifests/base/deployment/argocd-image-updater-deployment.yaml b/manifests/base/deployment/argocd-image-updater-deployment.yaml index 4febed29..3fb5ad80 100644 --- a/manifests/base/deployment/argocd-image-updater-deployment.yaml +++ b/manifests/base/deployment/argocd-image-updater-deployment.yaml @@ -83,6 +83,12 @@ spec: key: git.commit-signing-key name: argocd-image-updater-config optional: true + - name: GIT_COMMIT_SIGNING_METHOD + valueFrom: + configMapKeyRef: + key: git.commit-signing-key + name: argocd-image-updater-config + optional: true - name: GIT_COMMIT_SIGN_OFF valueFrom: configMapKeyRef: @@ -132,10 +138,6 @@ spec: mountPath: /app/.ssh/id_rsa readOnly: true subPath: sshPrivateKey - - name: ssh-signing-key - mountPath: /app/.ssh/id_rsa.pub - readOnly: true - subPath: sshPublicKey serviceAccountName: argocd-image-updater volumes: - configMap: diff --git a/manifests/install.yaml b/manifests/install.yaml index 47b9e01f..abf5f151 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -164,6 +164,12 @@ spec: key: git.commit-signing-key name: argocd-image-updater-config optional: true + - name: GIT_COMMIT_SIGNING_METHOD + valueFrom: + configMapKeyRef: + key: git.commit-signing-key + name: argocd-image-updater-config + optional: true - name: GIT_COMMIT_SIGN_OFF valueFrom: configMapKeyRef: @@ -215,10 +221,6 @@ spec: name: ssh-signing-key readOnly: true subPath: sshPrivateKey - - mountPath: /app/.ssh/id_rsa.pub - name: ssh-signing-key - readOnly: true - subPath: sshPublicKey serviceAccountName: argocd-image-updater volumes: - configMap: diff --git a/pkg/argocd/git.go b/pkg/argocd/git.go index 4ced14e6..1764a454 100644 --- a/pkg/argocd/git.go +++ b/pkg/argocd/git.go @@ -169,14 +169,6 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, changeLis } } - // Set commit signing configuration - if wbc.GitCommitSigningKey != "" { - err = gitC.SigningConfig(wbc.GitCommitSigningKey) - if err != nil { - return err - } - } - // The branch to checkout is either a configured branch in the write-back // config, or taken from the application spec's targetRevision. If the // target revision is set to the special value HEAD, or is the empty @@ -246,6 +238,7 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, changeLis commitOpts.SigningKey = wbc.GitCommitSigningKey } + commitOpts.SigningMethod = wbc.GitCommitSigningMethod commitOpts.SignOff = wbc.GitCommitSignOff err = gitC.Commit("", commitOpts) diff --git a/pkg/argocd/update.go b/pkg/argocd/update.go index 43f5c7d6..3f6f2530 100644 --- a/pkg/argocd/update.go +++ b/pkg/argocd/update.go @@ -36,19 +36,20 @@ type ImageUpdaterResult struct { } type UpdateConfiguration struct { - NewRegFN registry.NewRegistryClient - ArgoClient ArgoCD - KubeClient *kube.KubernetesClient - UpdateApp *ApplicationImages - DryRun bool - GitCommitUser string - GitCommitEmail string - GitCommitMessage *template.Template - GitCommitSigningKey string - GitCommitSignOff bool - DisableKubeEvents bool - IgnorePlatforms bool - GitCreds git.CredsStore + NewRegFN registry.NewRegistryClient + ArgoClient ArgoCD + KubeClient *kube.KubernetesClient + UpdateApp *ApplicationImages + DryRun bool + GitCommitUser string + GitCommitEmail string + GitCommitMessage *template.Template + GitCommitSigningKey string + GitCommitSigningMethod string + GitCommitSignOff bool + DisableKubeEvents bool + IgnorePlatforms bool + GitCreds git.CredsStore } type GitCredsSource func(app *v1alpha1.Application) (git.Creds, error) @@ -65,19 +66,20 @@ type WriteBackConfig struct { Method WriteBackMethod ArgoClient ArgoCD // If GitClient is not nil, the client will be used for updates. Otherwise, a new client will be created. - GitClient git.Client - GetCreds GitCredsSource - GitBranch string - GitWriteBranch string - GitCommitUser string - GitCommitEmail string - GitCommitMessage string - GitCommitSigningKey string - GitCommitSignOff bool - KustomizeBase string - Target string - GitRepo string - GitCreds git.CredsStore + GitClient git.Client + GetCreds GitCredsSource + GitBranch string + GitWriteBranch string + GitCommitUser string + GitCommitEmail string + GitCommitMessage string + GitCommitSigningKey string + GitCommitSigningMethod string + GitCommitSignOff bool + KustomizeBase string + Target string + GitRepo string + GitCreds git.CredsStore } // The following are helper structs to only marshal the fields we require @@ -337,6 +339,7 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat if updateConf.GitCommitSigningKey != "" { wbc.GitCommitSigningKey = updateConf.GitCommitSigningKey } + wbc.GitCommitSigningMethod = updateConf.GitCommitSigningMethod wbc.GitCommitSignOff = updateConf.GitCommitSignOff } From 065d6a5a365d7ec5869a3e6f75cc806eef15bde2 Mon Sep 17 00:00:00 2001 From: Dustin Lactin Date: Tue, 18 Jun 2024 11:47:52 -0600 Subject: [PATCH 3/3] fix: changed configMaptKeyRef for GIT_COMMIT_SIGNING_METHOD to git.commit-signing-method Signed-off-by: Dustin Lactin --- manifests/base/deployment/argocd-image-updater-deployment.yaml | 2 +- manifests/install.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/base/deployment/argocd-image-updater-deployment.yaml b/manifests/base/deployment/argocd-image-updater-deployment.yaml index 3fb5ad80..24bd7ced 100644 --- a/manifests/base/deployment/argocd-image-updater-deployment.yaml +++ b/manifests/base/deployment/argocd-image-updater-deployment.yaml @@ -86,7 +86,7 @@ spec: - name: GIT_COMMIT_SIGNING_METHOD valueFrom: configMapKeyRef: - key: git.commit-signing-key + key: git.commit-signing-method name: argocd-image-updater-config optional: true - name: GIT_COMMIT_SIGN_OFF diff --git a/manifests/install.yaml b/manifests/install.yaml index abf5f151..97167ec0 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -167,7 +167,7 @@ spec: - name: GIT_COMMIT_SIGNING_METHOD valueFrom: configMapKeyRef: - key: git.commit-signing-key + key: git.commit-signing-method name: argocd-image-updater-config optional: true - name: GIT_COMMIT_SIGN_OFF