Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for ssh signed commits and completed gpg signed commit work #710

Merged
merged 3 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 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,11 +14,14 @@ eec
fbd
ffb
gitlab
GPG
helmvalues
html
installationid
jfrog
mep
myregistry
openpgp
PRIVATEKEYDATA
repocreds
rollbacked
Expand Down
41 changes: 22 additions & 19 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +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
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
Expand Down
26 changes: 16 additions & 10 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ 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 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")

Expand Down Expand Up @@ -319,16 +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,
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
Expand Down
52 changes: 52 additions & 0 deletions docs/basics/update-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,58 @@ 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 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 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.
dlactin marked this conversation as resolved.
Show resolved Hide resolved

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)

### 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:**

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 private key:

```yaml
data:
git.commit-sign-off: "true"
git.commit-signing-key: /app/.ssh/id_rsa
git.commit-signing-method: "ssh"
```

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
```

**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
data:
git.commit-sign-off: "true"
git.commit-signing-key: 3AA5C34371567BD2
```

#### Commit Sign Off can be enabled by setting `git.commit-sign-off: "true"`

### <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
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.

16 changes: 10 additions & 6 deletions ext/git/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,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 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
}
Expand All @@ -25,16 +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 != "" {
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")
}
Expand Down
26 changes: 26 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,24 @@ 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_SIGNING_METHOD
valueFrom:
configMapKeyRef:
key: git.commit-signing-key
dlactin marked this conversation as resolved.
Show resolved Hide resolved
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 +134,10 @@ spec:
name: ssh-config
- mountPath: /tmp
name: tmp
- name: ssh-signing-key
mountPath: /app/.ssh/id_rsa
readOnly: true
subPath: sshPrivateKey
serviceAccountName: argocd-image-updater
volumes:
- configMap:
Expand All @@ -135,5 +157,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
26 changes: 26 additions & 0 deletions manifests/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,24 @@ 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_SIGNING_METHOD
valueFrom:
configMapKeyRef:
key: git.commit-signing-key
dlactin marked this conversation as resolved.
Show resolved Hide resolved
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 +217,10 @@ spec:
name: ssh-config
- mountPath: /tmp
name: tmp
- mountPath: /app/.ssh/id_rsa
name: ssh-signing-key
readOnly: true
subPath: sshPrivateKey
serviceAccountName: argocd-image-updater
volumes:
- configMap:
Expand All @@ -218,5 +240,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
7 changes: 7 additions & 0 deletions pkg/argocd/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,13 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, changeLis
defer os.Remove(cm.Name())
}

if wbc.GitCommitSigningKey != "" {
commitOpts.SigningKey = wbc.GitCommitSigningKey
}

commitOpts.SigningMethod = wbc.GitCommitSigningMethod
commitOpts.SignOff = wbc.GitCommitSignOff

err = gitC.Commit("", commitOpts)
if err != nil {
return err
Expand Down
Loading
Loading