Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 13 additions & 0 deletions .github/workflows/functional-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ jobs:
values: ci/functional/values/filesystem.yaml
- backend: transient
values: ci/functional/values/transient.yaml
- backend: auth-existing-secret
values: ci/functional/values/auth-existing-secret.yaml
authSecret: true
- backend: azureblob
values: ci/functional/values/azureblob.yaml
mock: ci/functional/mocks/azurite.yaml
Expand Down Expand Up @@ -111,6 +114,16 @@ jobs:
--from-file=keystore.p12=/tmp/keystore.p12 \
--from-literal=keystore-password=changeit

- name: Create client auth Secret (auth existingSecret leg)
if: matrix.authSecret
# The identity/secret the smoke test signs with, in the Secret the chart
# references via config.auth.existingSecret. Broken wiring leaves
# s3proxy.identity/credential unset and the round-trip fails to authenticate.
run: |
kubectl -n "${NAMESPACE}" create secret generic s3proxy-auth \
--from-literal=accessKeyId='test-access-key' \
--from-literal=secretAccessKey='test-secret-key'

- name: Create Azure Blob key Secret (existingSecret leg)
if: matrix.azureKeySecret
# Azurite's devstoreaccount1 key in the Secret the chart references via
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/lint-render.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
- test-values/s3.yaml
- test-values/azureblob.yaml
- test-values/azureblob-existing-secret.yaml
- test-values/auth-existing-secret.yaml
- test-values/azureblob-managed-identity.yaml
- test-values/gcs.yaml
- test-values/b2.yaml
Expand Down
2 changes: 1 addition & 1 deletion charts/s3proxy/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.4.3
version: 0.5.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
Expand Down
37 changes: 36 additions & 1 deletion charts/s3proxy/README.md.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,41 @@ persistence:
enabled: false
```

## Client authentication credentials

`config.auth.identity` / `config.auth.secret` are the S3 Access Key ID and Secret
Access Key that *clients* present to S3Proxy.

### Option A: existing Secret (recommended)

Point `config.auth.existingSecret` at a Secret you manage yourself, so the credentials
never appear in the values file (e.g. in GitOps). It takes precedence over inline
`identity`/`secret`; both credentials are read from it:

```yaml
config:
auth:
type: "aws-v4"
existingSecret: my-s3proxy-auth
identityKey: accessKeyId # default; key holding the Access Key ID
secretKey: secretAccessKey # default; key holding the Secret Access Key
```

```bash
kubectl create secret generic my-s3proxy-auth \
--from-literal=accessKeyId='myaccesskey' \
--from-literal=secretAccessKey='mysecretkey'
```

Rotating the Secret does not restart the pod — roll the Deployment yourself, since the
credentials are read once at startup.

### Option B: inline credentials

Set `config.auth.identity` / `config.auth.secret` directly, as in
[Example 1](#example-1-filesystem-backend-with-authentication). Convenient for
testing; both values are stored in plaintext in the chart's own Secret.

## Testing the Installation

Once deployed, you can test S3Proxy using the AWS CLI:
Expand Down Expand Up @@ -426,7 +461,7 @@ This will remove all resources created by the chart. If using persistence, the P

### Common Issues

1. **Authentication failures**: Ensure `config.auth.identity` and `config.auth.secret` are set correctly for client authentication.
1. **Authentication failures**: Ensure `config.auth.identity` and `config.auth.secret` are set correctly (or, with `config.auth.existingSecret`, that the Secret exists and its `identityKey`/`secretKey` entries are present) for client authentication.

2. **Backend connection issues**: Verify backend credentials are correctly configured in the appropriate section (e.g., `config.backend.awsS3.*`).

Expand Down
5 changes: 5 additions & 0 deletions charts/s3proxy/override-values.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ config:
# These should be changed to secure values
identity: "admin"
secret: "changeme123"
# Or keep them out of this file entirely and read both from a Secret you
# manage (takes precedence over the inline values above):
# existingSecret: "my-s3proxy-auth"
# identityKey: "accessKeyId"
# secretKey: "secretAccessKey"

# Native in-pod HTTPS (S3Proxy secure-endpoint). When enabled, S3Proxy serves
# HTTPS only on service.targetPort; TLS is terminated in the pod rather than at
Expand Down
4 changes: 2 additions & 2 deletions charts/s3proxy/templates/NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@
{{- if .Values.config.backends.filesystem.enabled }}
- Using filesystem backend at: {{ .Values.config.backends.filesystem.basedir }}
{{- end }}
{{- if not .Values.config.auth.identity }}
- WARNING: S3Proxy identity not configured. Remember to set config.auth.identity and config.auth.secret for authentication.
{{- if and (not .Values.config.auth.identity) (not .Values.config.auth.existingSecret) }}
- WARNING: S3Proxy identity not configured. Remember to set config.auth.identity and config.auth.secret (or config.auth.existingSecret) for authentication.
{{- end }}
{{- if .Values.config.backends.s3.enabled }}
- Make sure to configure S3 backend credentials
Expand Down
27 changes: 27 additions & 0 deletions charts/s3proxy/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,18 @@ spec:
cat "$COMMON_SECRET" >> "$output_file"
fi

# Client auth from config.auth.existingSecret: each file under
# /auth-secret/ is named for the S3Proxy property it holds.
if [ -d "/auth-secret" ]
then
for prop_file in /auth-secret/*
do
[ -f "$prop_file" ] || continue
echo "" >> "$output_file" # Add newline separator
printf '%s=%s\n' "$(basename "$prop_file")" "$(cat "$prop_file")" >> "$output_file"
done
fi

# Append this backend's own secret: backend-<name>.properties
# pairs with secret-<name>.properties
backend="${filename#backend-}"
Expand Down Expand Up @@ -122,6 +134,11 @@ spec:
mountPath: /tls-password
readOnly: true
{{- end }}
{{- if .Values.config.auth.existingSecret }}
- name: auth-secret
mountPath: /auth-secret
readOnly: true
{{- end }}
{{- range $s := (include "s3proxy.externalBackendSecrets" . | fromJsonArray) }}
- name: {{ $s.name }}
mountPath: /backend-secret/{{ $s.backend }}/{{ $s.prop }}
Expand Down Expand Up @@ -291,6 +308,16 @@ spec:
- key: {{ .Values.config.backends.googleCloudStorage.privateKey.secretKey }}
path: gcs-private.key
{{- end }}
{{- if .Values.config.auth.existingSecret }}
- name: auth-secret
secret:
secretName: {{ .Values.config.auth.existingSecret }}
items:
- key: {{ .Values.config.auth.identityKey }}
path: s3proxy.identity
- key: {{ .Values.config.auth.secretKey }}
path: s3proxy.credential
{{- end }}
{{- range $s := (include "s3proxy.externalBackendSecrets" . | fromJsonArray) }}
- name: {{ $s.name }}
secret:
Expand Down
14 changes: 13 additions & 1 deletion charts/s3proxy/templates/secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ data:
# into the text properties. Used only when keystore.existingSecret is empty.
{{ .Values.config.tls.keystore.secretKey }}: {{ .Values.config.tls.keystore.value }}
{{- end }}
{{- with include "s3proxy.secret.stringData" . }}
stringData:
# Sensitive properties merged into the backend properties files by the
# merge-configs initContainer:
Expand All @@ -20,7 +21,17 @@ stringData:
# each backend gets its own jclouds.credential and never another backend's.
# Local backends (filesystem/transient) need no secret file; their placeholder
# jclouds.identity/credential come from the ConfigMap.
{{- $hasClientAuth := and .Values.config.auth.identity .Values.config.auth.secret }}
{{- . }}
{{- end }}

{{- /*
The stringData properties, captured so the key above is emitted only when non-empty
(with every credential coming from an existingSecret, or auth disabled, a bare
`stringData:` would render as null). Client auth from config.auth.existingSecret is
mounted at /auth-secret and merged by the initContainer instead of landing here.
*/}}
{{- define "s3proxy.secret.stringData" -}}
{{- $hasClientAuth := and .Values.config.auth.identity .Values.config.auth.secret (not .Values.config.auth.existingSecret) }}
{{- $inlineKeystorePassword := and .Values.config.tls.enabled .Values.config.tls.keystorePassword.value (not .Values.config.tls.keystorePassword.existingSecret) }}
{{- if or $hasClientAuth $inlineKeystorePassword }}
secret-common.properties: |
Expand Down Expand Up @@ -71,3 +82,4 @@ stringData:
# Rackspace Cloud Files backend credential
jclouds.credential={{ .Values.config.backends.rackspaceCloudfiles.apiKey.value }}
{{- end }}
{{- end }}
10 changes: 8 additions & 2 deletions charts/s3proxy/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,16 @@ config:
auth:
# -- Authorization type (none, aws-v2, aws-v4, aws-v2-or-v4)
type: "aws-v4"
# -- S3 Access Key ID for client authentication
# -- S3 Access Key ID for client authentication, stored in the chart-owned Secret. Ignored when `existingSecret` is set.
identity: ""
# -- S3 Secret Access Key for client authentication
# -- S3 Secret Access Key for client authentication, stored in the chart-owned Secret. Ignored when `existingSecret` is set.
secret: ""
# -- Name of an existing Secret holding both client authentication credentials (see `identityKey`/`secretKey`). Takes precedence over `identity`/`secret`, which are otherwise stored in plaintext in the chart-owned Secret; prefer this when the values file lives in Git.
existingSecret: ""
# -- Key within `existingSecret` that holds the S3 Access Key ID
identityKey: "accessKeyId"
# -- Key within `existingSecret` that holds the S3 Secret Access Key
secretKey: "secretAccessKey"

tls:
# -- Enable native in-pod HTTPS (S3Proxy `secure-endpoint`). When enabled, S3Proxy serves HTTPS only on `service.targetPort` (the plaintext endpoint is not bound), so TLS is terminated in the pod rather than at the ingress. Requires a PKCS12 (or JKS) keystore and its password. `tcpSocket` health probes are unaffected (they do not perform a TLS handshake).
Expand Down
20 changes: 20 additions & 0 deletions ci/functional/values/auth-existing-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Functional-test values: client auth sourced from a pre-existing Secret
# (config.auth.existingSecret, default identityKey/secretKey) on a self-contained
# filesystem backend. The workflow creates the Secret with the credentials the smoke
# test signs with.
config:
auth:
type: aws-v4
existingSecret: s3proxy-auth
backends:
filesystem:
enabled: true
nio2: true
basedir: /data/s3proxy
persistence:
enabled: true
size: 1Gi
resources:
requests:
cpu: 100m
memory: 256Mi
14 changes: 14 additions & 0 deletions test-values/auth-existing-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Render/lint scenario: S3Proxy client credentials from a pre-existing Secret instead
# of inline values, so they never land in the values file (and thus in Git).
config:
logLevel: INFO
auth:
type: aws-v4
existingSecret: my-s3proxy-auth
backends:
filesystem:
enabled: true
nio2: true
basedir: /data/s3proxy
persistence:
enabled: false
Loading