Skip to content

Commit

Permalink
Added support for ssh signed commits and completed gpg signed commit …
Browse files Browse the repository at this point in the history
…work

Signed-off-by: Dustin Lactin <[email protected]>
  • Loading branch information
dlactin committed Jun 3, 2024
1 parent 3f47c8b commit 759efce
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 32 deletions.
5 changes: 5 additions & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
aeece
Artifactory
applicationid
atlassian
Bitbucket
bitbucketserver
bacd
CVE
credref
Expand All @@ -11,7 +14,9 @@ eec
fbd
ffb
gitlab
GPG
helmvalues
html
installationid
jfrog
mep
Expand Down
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type ImageUpdaterConfig struct {
GitCommitUser string
GitCommitMail string
GitCommitMessage *template.Template
GitCommitSigningKey string
GitCommitSignOff bool
DisableKubeEvents bool
}

Expand Down
22 changes: 13 additions & 9 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,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", "[email protected]"), "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")

Expand Down Expand Up @@ -300,15 +302,17 @@ 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,
DisableKubeEvents: cfg.DisableKubeEvents,
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,
}
res := argocd.UpdateApplication(upconf, syncState)
result.NumApplicationsProcessed += 1
Expand Down
49 changes: 48 additions & 1 deletion docs/basics/update-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
```

### <a name="method-git-repository"></a>Specifying a repository when using a Helm repository in repoURL
Expand Down Expand Up @@ -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.

### <a name="method-git-commit-signing"></a>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
```

### <a name="method-git-commit-message"></a>Changing the Git commit message

You can change the default commit message used by Argo CD Image Updater to some
Expand Down
1 change: 1 addition & 0 deletions ext/git/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
14 changes: 14 additions & 0 deletions ext/git/mocks/Client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 37 additions & 2 deletions ext/git/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package git

import (
"fmt"
"regexp"
"strings"

"github.com/argoproj-labs/argocd-image-updater/pkg/log"
Expand All @@ -13,7 +14,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
Expand All @@ -32,7 +33,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")
Expand Down Expand Up @@ -116,3 +126,28 @@ func (m *nativeGitClient) Config(username string, email string) error {

return nil
}

// 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
}
24 changes: 24 additions & 0 deletions manifests/base/deployment/argocd-image-updater-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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
24 changes: 24 additions & 0 deletions manifests/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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
14 changes: 14 additions & 0 deletions pkg/argocd/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 759efce

Please sign in to comment.