Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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
42 changes: 42 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Test infrastructure (causes permission issues)
test-infrastructure/

# Git files
.git/
.gitignore

# Documentation
*.md
docs/

# Examples (not needed for build)
examples/

# Test files
*_test.go
test/

# IDE files
.vscode/
.idea/
*.swp
*.swo

# OS files
.DS_Store
Thumbs.db

# Build artifacts
bin/
dist/
*.exe
*.dll
*.so
*.dylib

# Logs
*.log

# Temporary files
tmp/
temp/
22 changes: 22 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Build stage
FROM golang:1.19-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /secretize ./cmd/secretize

# Final stage
FROM alpine:3.18

# Install ca-certificates for HTTPS connections
RUN apk --no-cache add ca-certificates

COPY --from=builder /secretize /usr/local/bin/secretize

# KRM functions run as nobody user
USER nobody

ENTRYPOINT ["/usr/local/bin/secretize"]
107 changes: 107 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,31 @@ It is possible to use multiple providers at once.

## Installation

Secretize now supports multiple installation methods:

### Method 1: KRM Function (Recommended)

Secretize supports modern Kubernetes Resource Model (KRM) Functions, which work with Kustomize 4.0.0+:

#### Exec KRM Function
Download the binary and use it directly:
```bash
curl -L https://github.com/bbl/secretize/releases/download/v0.0.1/secretize-v0.0.1-linux-amd64.tar.gz | tar -xz
chmod +x secretize
```

#### Containerized KRM Function
Use the Docker image (no installation required):
```yaml
# In your kustomization, reference the container image
annotations:
config.kubernetes.io/function: |
container:
image: ghcr.io/bbl/secretize:latest
```

### Method 2: Legacy Plugin (Deprecated)

Install secretize to your `$XDG_CONFIG_HOME/kustomize/plugin` folder:

1. Export the `XDG_CONFIG_HOME` variable if it's not already set:
Expand All @@ -48,6 +73,62 @@ curl -L https://github.com/bbl/secretize/releases/download/v0.0.1/secretize-v0.0

## Usage

### Using KRM Functions (Recommended)

With KRM functions, add the `config.kubernetes.io/function` annotation to your SecretGenerator:

#### Exec KRM Function Example
```yaml
# secret-generator.yaml
apiVersion: secretize/v1
kind: SecretGenerator
metadata:
name: my-secrets
annotations:
config.kubernetes.io/function: |
exec:
path: ./secretize
sources:
- provider: env
literals:
- DATABASE_URL
```

Run with: `kustomize build --enable-alpha-plugins --enable-exec .`

#### Containerized KRM Function Example
```yaml
# secret-generator.yaml
apiVersion: secretize/v1
kind: SecretGenerator
metadata:
name: my-secrets
annotations:
config.kubernetes.io/function: |
container:
image: ghcr.io/bbl/secretize:latest
sources:
- provider: env
literals:
- DATABASE_URL
```

Run with: `kustomize build --enable-alpha-plugins .`

### Legacy Plugin Usage

For the legacy plugin, use without annotations:

```yaml
# kustomization.yaml
generators:
- secret-generator.yaml
```

Run with: `kustomize build --enable-alpha-plugins .`

### Provider Configuration

All providers can generate two types of secrets: `literals` and `kv` (Key-Value secrets).
Literal secrets simply generate a single string output, while KV secrets will output with a dictionary of the key-value pairs.

Expand Down Expand Up @@ -279,3 +360,29 @@ data:
secret_key_1: c2VjcmV0X3ZhbHVlXzE=
secret_key_2: c2VjcmV0X3ZhbHVlXzI=
```

## Examples

Check out the [examples](./examples) directory for complete working examples:

- [Legacy Plugin Example](./examples/legacy) - Traditional Kustomize plugin approach
- [Exec KRM Function Example](./examples/exec) - Modern exec-based KRM function
- [Containerized KRM Function Example](./examples/docker) - Docker-based KRM function

## Test Infrastructure

For comprehensive testing with real secret stores, see the [test-infrastructure](./test-infrastructure/) directory which provides:

- **HashiCorp Vault** setup with test secrets
- **AWS Secrets Manager** emulation via LocalStack
- **Kubernetes** cluster with test secrets
- **Automated testing** for all providers and execution modes

```bash
cd test-infrastructure
./test-all-providers.sh
```

## Documentation

For detailed documentation on KRM Functions support, see [KRM Functions Documentation](./docs/KRM_FUNCTIONS.md).
86 changes: 83 additions & 3 deletions cmd/secretize/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,40 @@ package main

import (
"fmt"
"io/ioutil"

"github.com/bbl/secretize/pkg/generator"
"github.com/bbl/secretize/pkg/utils"
log "github.com/sirupsen/logrus"
"io/ioutil"

"os"
"path/filepath"

"sigs.k8s.io/kustomize/kyaml/fn/framework"
"sigs.k8s.io/kustomize/kyaml/fn/framework/command"
"sigs.k8s.io/kustomize/kyaml/yaml"
)

func main() {
// Check if running as KRM function (no args or stdin has content)
if len(os.Args) == 1 || isKRMFunction() {
runAsKRMFunction()
} else {
// Legacy mode
runLegacyMode()
}
}

// isKRMFunction checks if stdin has content (indicating KRM function mode)
func isKRMFunction() bool {
stat, _ := os.Stdin.Stat()
return (stat.Mode() & os.ModeCharDevice) == 0
}

// runLegacyMode runs the original secretize behavior
func runLegacyMode() {
if len(os.Args) < 2 {
log.Fatal(
"No argument passed, use `secretize /path/to/generator-config.yaml`")
log.Fatal("No argument passed, use `secretize /path/to/generator-config.yaml`")
}

filename, _ := filepath.Abs(os.Args[1])
Expand All @@ -33,3 +53,63 @@ func main() {
utils.FatalErrCheck(err)
fmt.Println(out)
}

// SecretGeneratorProcessor implements the KRM function processor
type SecretGeneratorProcessor struct{}

// Process implements the framework.ResourceListProcessor interface
func (p SecretGeneratorProcessor) Process(rl *framework.ResourceList) error {
// Get the function config
if rl.FunctionConfig == nil {
return fmt.Errorf("no function config provided")
}

// Convert function config to YAML string
fcString, err := rl.FunctionConfig.String()
if err != nil {
return fmt.Errorf("failed to marshal function config: %w", err)
}

// Parse as SecretGenerator
secretGenerator, err := generator.ParseConfig([]byte(fcString))
if err != nil {
return fmt.Errorf("failed to parse config: %w", err)
}

// Generate secrets
secrets, err := secretGenerator.FetchSecrets(generator.ProviderRegistry)
if err != nil {
return fmt.Errorf("failed to fetch secrets: %w", err)
}

// Generate the secret resource
secret := secretGenerator.Generate(secrets)
secretYaml, err := secret.ToYamlStr()
if err != nil {
return fmt.Errorf("failed to convert secret to yaml: %w", err)
}

// Parse the generated secret as RNode
rNode, err := yaml.Parse(secretYaml)
if err != nil {
return fmt.Errorf("failed to parse generated secret: %w", err)
}

// Append to items
rl.Items = append(rl.Items, rNode)

return nil
}

// runAsKRMFunction runs secretize as a KRM function
func runAsKRMFunction() {
processor := SecretGeneratorProcessor{}
cmd := command.Build(processor, command.StandaloneDisabled, false)

// Add dockerfile generation support
command.AddGenerateDockerfile(cmd)

if err := cmd.Execute(); err != nil {
os.Exit(1)
}
}
80 changes: 80 additions & 0 deletions examples/docker/env/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Containerized KRM Function Example (Environment Variables)

This example demonstrates how to use Secretize as a containerized KRM function with Kustomize, sourcing secrets from environment variables set directly in the function config.

---

## How It Works

- The containerized KRM function runs in an isolated environment and **does not inherit environment variables from your shell**.
- All required environment variables must be set explicitly in the `envs:` section of the function config in `secret-generator.yaml`.
- This approach is simple, reproducible, and works reliably with Kustomize and Secretize.

---

## Step-by-Step Usage

1. **(Optional) Build the Secretize Docker image (if using `image: secretize:local`):**
```bash
cd ../../..
docker build -t secretize:local .
cd examples/docker/env
```

2. **Export the required environment variables in your shell:**
```bash
export DATABASE_URL="postgresql://user:pass@localhost/db"
export API_KEY="your-secret-api-key"
export JWT_SECRET="your-jwt-secret"
export CONFIG_JSON='{"feature_new_ui": "true", "feature_beta": "false"}'
```
These variables will be referenced by the YAML configuration.

3. **Reference the environment variables in your YAML file:**
In `secret-generator.yaml`, you can reference these variables using the `literals` and `kv` fields:
```yaml
sources:
- provider: env
literals:
- DATABASE_URL # Reads from $DATABASE_URL
- API_KEY # Reads from $API_KEY
- JWT_SECRET # Reads from $JWT_SECRET
kv:
- CONFIG_JSON # Reads from $CONFIG_JSON and parses as JSON
```
- `literals`: Direct environment variable values
- `kv`: Environment variables containing JSON that gets parsed into key-value pairs

4. **Run Kustomize build with containerized KRM function enabled:**
```bash
kustomize build --enable-alpha-plugins .
```

---

## Why Not YAML Anchors for Env Vars?
- YAML anchors are useful for repeating static YAML blocks, but **they do not help with dynamic environment variable substitution**.
- For dynamic values, set them directly in the `envs:` list as shown above.
- If you want to use exported environment variables from your shell, use the [exec approach](../exec/env/README.md) instead.

---

## Troubleshooting

- If secrets are not found, make sure you set all required env vars in the function config.
- If you see an error about `secretize:local` not found, make sure you built the image as described above.
- If you see errors about `$` or `${VAR}` in the output, make sure you have replaced all placeholders with actual values.

---

## Security Considerations

- **Never hardcode real secrets in your configs for production.**
- Use this approach for local development, testing, or with non-sensitive values.
- For production, consider using a secrets manager (like Vault) and the appropriate Secretize provider.

---

## Reference: Using Host Environment Variables

- If you want to use environment variables exported in your shell, use the [exec KRM function approach](../exec/env/README.md), which can access your host environment directly.
Loading