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

add functionality to fetch private remote base using ssh secrets #2

Merged
merged 8 commits into from
Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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
36 changes: 23 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
# build stage
FROM golang:1-alpine AS build

RUN apk --no-cache add git gcc make musl-dev curl bash openssh-client
FROM golang:1 AS build

ENV \
STRONGBOX_VERSION=master \
KUSTOMIZE_VERSION=v4.5.5

RUN os=$(go env GOOS) && arch=$(go env GOARCH) \
&& curl -Ls https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_${os}_${arch}.tar.gz \
| tar xz -C /usr/local/bin/ \
&& chmod +x /usr/local/bin/kustomize \
RUN go install sigs.k8s.io/kustomize/kustomize/v4@${KUSTOMIZE_VERSION} \
george-angel marked this conversation as resolved.
Show resolved Hide resolved
&& go install github.com/uw-labs/strongbox@${STRONGBOX_VERSION}

ADD . /argocd-strongbox-plugin
ADD . /app

WORKDIR /argocd-strongbox-plugin
WORKDIR /app


RUN go test -v ./... \
RUN go test -v -cover ./... \
&& go build -o /argocd-strongbox-plugin .

# final stage
FROM alpine:latest
# argocd requires that sidecar container is running as user 999
FROM ubuntu:22.04

USER root

ENV ARGOCD_USER_ID=999

RUN apk --no-cache add git openssh-client
RUN groupadd -g $ARGOCD_USER_ID argocd && \
useradd -r -u $ARGOCD_USER_ID -g argocd argocd && \
apt-get update && \
apt-get -y upgrade && \
apt-get install -y git git-lfs && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY --from=build \
/usr/local/bin/kustomize \
/go/bin/kustomize \
/go/bin/strongbox \
/usr/local/bin/

COPY --from=build /argocd-strongbox-plugin /usr/local/bin

ENV USER=argocd

USER $ARGOCD_USER_ID
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,31 @@ if multiple keys are used to encrypt app secrets then this secret should contain
### `generate`
command will run kustomize build to generate kube resources's yaml strings. it will print this yaml stream to stdout.

You can specify custom SSH keys to be used for fetching remote kustomize bases from private repositories. In order to do that,
you will need to set `GIT_SSH_SECRET_NAME` plugin env, it should reference a Secret name that contains one or more SSH keys
that provide access to the private repositories that contain these bases. if this env is not set then plugin will
only be able to fetch remote bases from open repositories.

To use an SSH key for Kustomize bases, the bases should be defined with the ssh:// scheme in kustomization.yaml and have a
`# argocd-strongbox-plugin: key_foobar` comment above it. For example:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is now a good time to rename the plugin? Its no longer just does Strongbox

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was also thinking about this. any suggestions?


```yaml
resources:
# https scheme (default if omitted), any SSH keys defined are ignored
- github.com/org/open1//manifests/lab-foo?ref=master

# ssh scheme requires a valid SSH key to be defined
# here keyA will be used to fetch repo1 and KeyB for repo2
# argocd-strongbox-plugin: keyA
- ssh://github.com/org/repo1//manifests/lab-foo?ref=master
# argocd-strongbox-plugin: KeyB
- ssh://github.com/org/repo2//manifests/lab-zoo?ref=dev
```

## Environment Variables

### Strongbox ENVs

Plugin supports following _plugin envs_ which can be set in ArgoCD Application crd

`STRONGBOX_SECRET_NAME` the value should be the name of a secret resource containing strongbox keyring used to encrypt app secrets. the default value is `argocd-strongbox-keyring`
Expand Down Expand Up @@ -59,6 +82,35 @@ spec:
value: .strongbox_keyring
```

### Git SSH Keys Envs

`GIT_SSH_SECRET_NAME` the value should be the name of a secret resource containing ssh keys used for fetching remote kustomize bases from private repositories. Additionally this Secret can optionally define a value for "known_hosts". If omitted, git will use ssh with StrictHostKeyChecking disabled. There is no default value for this env it must be set if repo base contains remote
private bases.

`GIT_SSH_SECRET_NAMESPACE` the value should be the name of a namespace where secret resource containing ssh keys are located. If this env is not specified then it defaults to the same namespace as the app's destination NS.
the Secret should have an annotation called "argocd-strongbox.plugin.io/allowed-namespaces" which contains a comma-separated list of all the namespaces that are allowed to use it.

```yaml
kind: Secret
apiVersion: v1
metadata:
name: argocd-git-ssh
namespace: ns-a
annotations:
kube-applier.io/allowed-namespaces: "ns-b, ns-c"
stringData:
keyA: |-
-----BEGIN OPENSSH PRIVATE KEY-----
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
-----END OPENSSH PRIVATE KEY-----
KeyB: |-
-----BEGIN OPENSSH PRIVATE KEY-----
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
-----END OPENSSH PRIVATE KEY-----
known_hosts: |-
github.com ssh-rsa AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
```

## Configuration and Installation plugin via sidecar
for more details please see [argocd-docs](https://argo-cd.readthedocs.io/en/latest/user-guide/config-management-plugins/#option-2-configure-plugin-via-sidecar).

Expand Down Expand Up @@ -86,10 +138,14 @@ data:
command:
- argocd-strongbox-plugin
- decrypt
args:
- "--secret-allowed-namespaces-annotation=argocd-strongbox.plugin.io/allowed-namespaces"
generate:
command:
- argocd-strongbox-plugin
- generate
args:
- "--secret-allowed-namespaces-annotation=argocd-strongbox.plugin.io/allowed-namespaces"
lockRepo: false
```

Expand Down
21 changes: 15 additions & 6 deletions decrypt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import (
)

var (
encryptedTestDir1 = "./testData/app-with-secrets-test1"
encryptedTestDir2 = "./testData/app-with-secrets-test2"
plainTextTestDir = "./testData/app-without-secrets"
encryptedTestDir1 = "./testData/app-with-secrets-test1"
encryptedTestDir2 = "./testData/app-with-secrets-test2"
withRemoteBaseTestDir = "./testData/app-with-remote-base-test1"
// withRemoteBase = "./testData/app-with-remote-base"
)

func getFileContent(t *testing.T, fileName string) []byte {
Expand All @@ -44,10 +45,18 @@ func TestMain(m *testing.M) {
os.Exit(1)
}

cmd = exec.Command("cp", "-r", "./testData/app-with-remote-base", withRemoteBaseTestDir)
out, err = cmd.CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "%v", string(out))
os.Exit(1)
}

code := m.Run()

os.RemoveAll(encryptedTestDir1)
os.RemoveAll(encryptedTestDir2)
os.RemoveAll(withRemoteBaseTestDir)

os.Exit(code)
}
Expand All @@ -64,7 +73,7 @@ func Test_hasEncryptedFiles(t *testing.T) {
}{
{"encryptedTestDir1", args{cwd: encryptedTestDir1}, true, false},
{"encryptedTestDir2", args{cwd: encryptedTestDir2}, true, false},
{"plainTextTestDir", args{cwd: plainTextTestDir}, false, false},
{"withRemoteBase", args{cwd: withRemoteBaseTestDir}, false, false},
{".github", args{cwd: ".github"}, false, false},
}
for _, tt := range tests {
Expand Down Expand Up @@ -165,7 +174,7 @@ func Test_ensureDecryption(t *testing.T) {
},
)

// plainTextTestDir doesn't have enc files so it should not look for "missing-secrets" secret
// withRemoteBase doesn't have enc files so it should not look for "missing-secrets" secret
bar := applicationInfo{
name: "bar",
destinationNamespace: "bar",
Expand All @@ -174,7 +183,7 @@ func Test_ensureDecryption(t *testing.T) {
key: "invalid",
},
}
err = ensureDecryption(context.Background(), plainTextTestDir, bar)
err = ensureDecryption(context.Background(), withRemoteBaseTestDir, bar)
if err != nil {
t.Fatal(err)
}
Expand Down
22 changes: 19 additions & 3 deletions generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,34 @@ import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"strings"
)

func ensureBuild(ctx context.Context, cwd string) (string, error) {
return runKustomizeBuild(ctx, cwd)
func ensureBuild(ctx context.Context, cwd string, app applicationInfo) (string, error) {
c, err := setupGitSSH(ctx, cwd, app)
if err != nil {
return "", err
}

//
env := os.Environ()

env = append(env, c)
// Set HOME to cwd, this means that SSH should not pick up any
// local SSH keys and use them for cloning
env = append(env, fmt.Sprintf("HOME=%s", cwd))

return runKustomizeBuild(ctx, cwd, env)
}

// runKustomizeBuild will run `kustomize build` cmd and return generated yaml or error
func runKustomizeBuild(ctx context.Context, cwd string) (string, error) {
func runKustomizeBuild(ctx context.Context, cwd string, env []string) (string, error) {
k := exec.CommandContext(ctx, "kustomize", "build", ".")

k.Dir = cwd
k.Env = env

var stdout bytes.Buffer
var stderr bytes.Buffer
Expand Down
21 changes: 0 additions & 21 deletions generate_test.go

This file was deleted.

Loading