mirror of
https://github.com/wahyd4/passkey-auth.git
synced 2026-08-08 20:15:44 +10:00
Add helm chart
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# Configuration for chart-releaser
|
||||
# See https://github.com/helm/chart-releaser for more info
|
||||
|
||||
owner: wahyd4
|
||||
git-repo: passkey-auth
|
||||
charts-repo: https://wahyd4.github.io/passkey-auth
|
||||
target-branch: gh-pages
|
||||
package-path: .cr-release-packages
|
||||
index-path: .cr-index
|
||||
skip-existing: true
|
||||
@@ -0,0 +1,95 @@
|
||||
name: Release Helm Chart
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'helm/passkey-auth/**'
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
lint-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v4
|
||||
with:
|
||||
version: '3.14.0'
|
||||
|
||||
- name: Set up chart-testing
|
||||
uses: helm/chart-testing-action@v2.6.1
|
||||
|
||||
- name: Run chart-testing (list)
|
||||
run: ct list --target-branch ${{ github.event.repository.default_branch }} --chart-dirs helm
|
||||
|
||||
- name: Run chart-testing (lint)
|
||||
run: ct lint --target-branch ${{ github.event.repository.default_branch }} --chart-dirs helm
|
||||
|
||||
- name: Create kind cluster
|
||||
uses: helm/kind-action@v1.9.0
|
||||
|
||||
- name: Run chart-testing (install)
|
||||
run: |
|
||||
# Install with test values
|
||||
ct install --target-branch ${{ github.event.repository.default_branch }} --chart-dirs helm \
|
||||
--helm-extra-set-args "--set config.webauthn.rpId=test.local --set config.auth.allowedEmails={test@example.com} --set secrets.sessionSecret=test-secret-for-ci-only --set ingress.enabled=false"
|
||||
|
||||
release:
|
||||
needs: lint-test
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main' || github.event_name == 'release'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "$GITHUB_ACTOR"
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@v4
|
||||
with:
|
||||
version: '3.14.0'
|
||||
|
||||
- name: Add helm repos
|
||||
run: |
|
||||
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||
|
||||
- name: Run chart-releaser
|
||||
uses: helm/chart-releaser-action@v1.6.0
|
||||
with:
|
||||
charts_dir: helm
|
||||
config: .github/cr.yaml
|
||||
env:
|
||||
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v4
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: .cr-release-packages
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
*.so
|
||||
*.dylib
|
||||
bin/
|
||||
passkey-auth
|
||||
./passkey-auth
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
# Hosting Passkey Auth Helm Chart on GitHub
|
||||
|
||||
This guide explains how to host your Helm chart on GitHub Pages and make it available via a public Helm repository.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- GitHub repository with your Helm chart
|
||||
- GitHub Actions enabled
|
||||
- GitHub Pages enabled
|
||||
|
||||
## Setup Steps
|
||||
|
||||
### 1. Repository Structure
|
||||
|
||||
Ensure your repository has this structure:
|
||||
```
|
||||
passkey-auth/
|
||||
├── .github/
|
||||
│ ├── workflows/
|
||||
│ │ └── helm-release.yml
|
||||
│ └── cr.yaml
|
||||
├── helm/
|
||||
│ └── passkey-auth/
|
||||
│ ├── Chart.yaml
|
||||
│ ├── values.yaml
|
||||
│ ├── README.md
|
||||
│ ├── templates/
|
||||
│ └── examples/
|
||||
└── README.md
|
||||
```
|
||||
|
||||
### 2. Enable GitHub Pages
|
||||
|
||||
1. Go to your GitHub repository
|
||||
2. Navigate to **Settings** > **Pages**
|
||||
3. Under **Source**, select **GitHub Actions**
|
||||
4. Save the configuration
|
||||
|
||||
### 3. Configure Repository Settings
|
||||
|
||||
1. **Enable GitHub Actions**:
|
||||
- Go to **Settings** > **Actions** > **General**
|
||||
- Enable "Allow all actions and reusable workflows"
|
||||
|
||||
2. **Set up GitHub Pages permissions**:
|
||||
- Go to **Settings** > **Actions** > **General**
|
||||
- Under "Workflow permissions", select "Read and write permissions"
|
||||
- Check "Allow GitHub Actions to create and approve pull requests"
|
||||
|
||||
### 4. Update Chart Configuration
|
||||
|
||||
Edit `.github/cr.yaml` to match your repository:
|
||||
|
||||
```yaml
|
||||
owner: YOUR_GITHUB_USERNAME # Change this
|
||||
git-repo: passkey-auth # Change if different
|
||||
charts-repo: https://YOUR_GITHUB_USERNAME.github.io/passkey-auth
|
||||
target-branch: gh-pages
|
||||
package-path: .cr-release-packages
|
||||
index-path: .cr-index
|
||||
skip-existing: true
|
||||
```
|
||||
|
||||
### 5. Create Your First Release
|
||||
|
||||
1. **Tag your first release**:
|
||||
```bash
|
||||
git tag v0.1.0
|
||||
git push origin v0.1.0
|
||||
```
|
||||
|
||||
2. **Or push changes to trigger workflow**:
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Add Helm chart"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
The GitHub Action will automatically:
|
||||
- Lint and test your chart
|
||||
- Package the chart
|
||||
- Create a GitHub release
|
||||
- Update the Helm repository index
|
||||
- Deploy to GitHub Pages
|
||||
|
||||
### 6. Verify the Setup
|
||||
|
||||
1. **Check GitHub Actions**:
|
||||
- Go to **Actions** tab in your repository
|
||||
- Verify the "Release Helm Chart" workflow completes successfully
|
||||
|
||||
2. **Check GitHub Pages**:
|
||||
- Go to **Settings** > **Pages**
|
||||
- You should see "Your site is published at https://username.github.io/passkey-auth"
|
||||
|
||||
3. **Test the Helm repository**:
|
||||
```bash
|
||||
helm repo add passkey-auth https://YOUR_USERNAME.github.io/passkey-auth
|
||||
helm repo update
|
||||
helm search repo passkey-auth
|
||||
```
|
||||
|
||||
## Using Your Hosted Chart
|
||||
|
||||
### Add the Repository
|
||||
|
||||
```bash
|
||||
helm repo add passkey-auth https://YOUR_USERNAME.github.io/passkey-auth
|
||||
helm repo update
|
||||
```
|
||||
|
||||
### Install the Chart
|
||||
|
||||
```bash
|
||||
# Basic installation
|
||||
helm install my-passkey-auth passkey-auth/passkey-auth
|
||||
|
||||
# With custom values
|
||||
helm install my-passkey-auth passkey-auth/passkey-auth \
|
||||
--set config.webauthn.rpId=auth.example.com \
|
||||
--set secrets.sessionSecret="your-secure-secret"
|
||||
|
||||
# With values file
|
||||
helm install my-passkey-auth passkey-auth/passkey-auth \
|
||||
-f values-production.yaml
|
||||
```
|
||||
|
||||
### Search Available Versions
|
||||
|
||||
```bash
|
||||
helm search repo passkey-auth --versions
|
||||
```
|
||||
|
||||
## Maintenance and Updates
|
||||
|
||||
### Releasing New Versions
|
||||
|
||||
1. **Update Chart.yaml**:
|
||||
```yaml
|
||||
version: 0.2.0 # Increment version
|
||||
appVersion: "v1.1.0" # Update app version if needed
|
||||
```
|
||||
|
||||
2. **Commit and push**:
|
||||
```bash
|
||||
git add helm/passkey-auth/Chart.yaml
|
||||
git commit -m "Bump chart version to 0.2.0"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
3. **The workflow will automatically**:
|
||||
- Package the new version
|
||||
- Create a GitHub release
|
||||
- Update the Helm repository
|
||||
|
||||
### Testing Charts Locally
|
||||
|
||||
```bash
|
||||
# Lint the chart
|
||||
helm lint helm/passkey-auth/
|
||||
|
||||
# Template the chart (dry run)
|
||||
helm template my-passkey-auth helm/passkey-auth/ \
|
||||
--set config.webauthn.rpId=test.local
|
||||
|
||||
# Install locally for testing
|
||||
helm install test-release helm/passkey-auth/ \
|
||||
--dry-run --debug
|
||||
```
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom Domain for Helm Repository
|
||||
|
||||
If you want to use a custom domain instead of `username.github.io`:
|
||||
|
||||
1. **Set up custom domain in GitHub Pages**:
|
||||
- Go to **Settings** > **Pages**
|
||||
- Add your custom domain (e.g., `charts.example.com`)
|
||||
|
||||
2. **Update `.github/cr.yaml`**:
|
||||
```yaml
|
||||
charts-repo: https://charts.example.com
|
||||
```
|
||||
|
||||
3. **Configure DNS**:
|
||||
- Add CNAME record pointing to `username.github.io`
|
||||
|
||||
### Multiple Charts in One Repository
|
||||
|
||||
If you have multiple charts:
|
||||
|
||||
```
|
||||
helm/
|
||||
├── passkey-auth/
|
||||
│ ├── Chart.yaml
|
||||
│ └── ...
|
||||
├── another-chart/
|
||||
│ ├── Chart.yaml
|
||||
│ └── ...
|
||||
```
|
||||
|
||||
The workflow will automatically detect and release all charts.
|
||||
|
||||
### Private Repositories
|
||||
|
||||
For private repositories, users will need:
|
||||
|
||||
1. **GitHub Personal Access Token**:
|
||||
```bash
|
||||
helm repo add passkey-auth https://username:TOKEN@username.github.io/passkey-auth
|
||||
```
|
||||
|
||||
2. **Or configure helm with auth**:
|
||||
```bash
|
||||
helm repo add passkey-auth https://username.github.io/passkey-auth \
|
||||
--username YOUR_USERNAME \
|
||||
--password YOUR_TOKEN
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **GitHub Actions Fails**:
|
||||
- Check workflow permissions in repository settings
|
||||
- Verify GitHub Pages is enabled
|
||||
- Check if there are syntax errors in the chart
|
||||
|
||||
2. **Chart Not Found**:
|
||||
- Verify the repository URL is correct
|
||||
- Check if GitHub Pages deployment completed
|
||||
- Ensure chart name matches directory name
|
||||
|
||||
3. **Permission Denied**:
|
||||
- Verify GitHub Actions has write permissions
|
||||
- Check if GitHub Pages is enabled for the repository
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# Check repository status
|
||||
helm repo list
|
||||
|
||||
# Update repositories
|
||||
helm repo update
|
||||
|
||||
# Debug template rendering
|
||||
helm template my-release helm/passkey-auth/ --debug
|
||||
|
||||
# Validate chart
|
||||
helm lint helm/passkey-auth/
|
||||
|
||||
# Check chart dependencies
|
||||
helm dependency list helm/passkey-auth/
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Repository Security
|
||||
|
||||
1. **Secrets Management**:
|
||||
- Never commit sensitive values to the repository
|
||||
- Use GitHub Secrets for sensitive configuration
|
||||
- Document security requirements in README
|
||||
|
||||
2. **Chart Signing** (Optional):
|
||||
```bash
|
||||
# Generate GPG key for chart signing
|
||||
gpg --gen-key
|
||||
|
||||
# Export public key
|
||||
gpg --armor --export your-email@example.com > public.key
|
||||
|
||||
# Add to chart-releaser config
|
||||
echo "sign: true" >> .github/cr.yaml
|
||||
```
|
||||
|
||||
3. **Dependency Security**:
|
||||
- Regularly update chart dependencies
|
||||
- Use dependency vulnerability scanning
|
||||
- Pin specific versions in production
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Version Management**:
|
||||
- Follow semantic versioning
|
||||
- Update `appVersion` when application changes
|
||||
- Update `version` when chart changes
|
||||
|
||||
2. **Documentation**:
|
||||
- Keep README.md updated
|
||||
- Document breaking changes
|
||||
- Provide migration guides
|
||||
|
||||
3. **Testing**:
|
||||
- Test charts before releasing
|
||||
- Use CI/CD for automated testing
|
||||
- Validate on different Kubernetes versions
|
||||
|
||||
## Example Repository
|
||||
|
||||
You can see a complete example at: `https://github.com/YOUR_USERNAME/passkey-auth`
|
||||
|
||||
The hosted Helm repository will be available at: `https://YOUR_USERNAME.github.io/passkey-auth`
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues:
|
||||
1. Check the GitHub Actions logs
|
||||
2. Verify chart syntax with `helm lint`
|
||||
3. Review GitHub Pages deployment status
|
||||
4. Open an issue in the repository for help
|
||||
@@ -20,13 +20,38 @@ A WebAuthn-based passkey authentication provider that integrates ingress control
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1. Build and Test Locally
|
||||
### Using Helm Chart (Recommended)
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd passkey-auth
|
||||
# Add the Helm repository
|
||||
helm repo add passkey-auth https://wahyd4.github.io/passkey-auth
|
||||
helm repo update
|
||||
|
||||
docker-compose up
|
||||
# Install with your configuration
|
||||
helm install my-passkey-auth passkey-auth/passkey-auth \
|
||||
--set config.webauthn.rpId=auth.example.com \
|
||||
--set config.webauthn.rpOrigins="{https://auth.example.com}" \
|
||||
--set config.cors.allowedOrigins="{https://*.example.com}" \
|
||||
--set config.auth.cookieDomain=".example.com" \
|
||||
--set config.auth.allowedEmails="{admin@example.com}" \
|
||||
--set ingress.hosts[0].host=auth.example.com \
|
||||
--set secrets.sessionSecret="your-secure-random-secret-key"
|
||||
|
||||
# Or use a values file
|
||||
helm install my-passkey-auth passkey-auth/passkey-auth -f values-production.yaml
|
||||
```
|
||||
|
||||
See the [Helm Chart README](helm/passkey-auth/README.md) for detailed configuration options.
|
||||
|
||||
|
||||
### Option 3: Local Development
|
||||
|
||||
```bash
|
||||
# Install dependencies and run locally
|
||||
go mod download
|
||||
go run main.go
|
||||
|
||||
# Access at http://localhost:8080
|
||||
```
|
||||
|
||||
### 2. Configure
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: v2
|
||||
name: passkey-auth
|
||||
description: A WebAuthn-based passkey authentication provider for Kubernetes Nginx Ingress
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "main"
|
||||
home: https://github.com/wahyd4/passkey-auth
|
||||
sources:
|
||||
- https://github.com/wahyd4/passkey-auth
|
||||
maintainers:
|
||||
- name: Junwei Zhao
|
||||
email: wahyd4@gmail.com
|
||||
keywords:
|
||||
- authentication
|
||||
- webauthn
|
||||
- passkey
|
||||
- nginx-ingress
|
||||
- security
|
||||
annotations:
|
||||
category: Security
|
||||
licenses: Apache-2.0
|
||||
@@ -0,0 +1,243 @@
|
||||
# Passkey Auth Helm Chart
|
||||
|
||||
A Helm chart for deploying Passkey Auth, a WebAuthn-based passkey authentication provider that integrates with Kubernetes Nginx Ingress controller.
|
||||
|
||||
## Overview
|
||||
|
||||
This chart deploys a secure, passwordless authentication service using WebAuthn/FIDO2 passkeys. It's designed to work as an authentication backend for nginx ingress controllers, providing enterprise-grade security without the complexity of traditional password-based systems.
|
||||
|
||||
## TL;DR
|
||||
|
||||
```bash
|
||||
helm repo add passkey-auth https://your-github-username.github.io/passkey-auth-helm
|
||||
helm repo update
|
||||
helm install my-passkey-auth passkey-auth/passkey-auth \
|
||||
--set config.webauthn.rpId=auth.example.com \
|
||||
--set config.webauthn.rpOrigins="{https://auth.example.com}" \
|
||||
--set secrets.sessionSecret="your-very-long-random-secret-key-here"
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.19+
|
||||
- Helm 3.0+
|
||||
- Nginx Ingress Controller
|
||||
- Cert-Manager (for TLS certificates)
|
||||
- StorageClass for persistent volumes
|
||||
|
||||
## Installation
|
||||
|
||||
### Add Helm Repository
|
||||
|
||||
```bash
|
||||
helm repo add passkey-auth https://your-github-username.github.io/passkey-auth-helm
|
||||
helm repo update
|
||||
```
|
||||
|
||||
|
||||
### Install from Local Chart
|
||||
|
||||
```bash
|
||||
git clone https://github.com/wahyd4/passkey-auth.git
|
||||
cd passkey-auth
|
||||
helm install my-passkey-auth ./helm/passkey-auth \
|
||||
--values ./helm/passkey-auth/values.yaml
|
||||
```
|
||||
|
||||
The command deploys Passkey Auth on the Kubernetes cluster with the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation.
|
||||
|
||||
> **Tip**: List all releases using `helm list`
|
||||
|
||||
## Configuration
|
||||
|
||||
### Core Configuration
|
||||
|
||||
The chart can be configured using the `values.yaml` file or by passing values via `--set` flags.
|
||||
|
||||
#### Required Configuration
|
||||
|
||||
```yaml
|
||||
config:
|
||||
webauthn:
|
||||
rpId: "auth.example.com" # Your authentication domain
|
||||
rpOrigins:
|
||||
- "https://auth.example.com" # Allowed origins for WebAuthn
|
||||
|
||||
cors:
|
||||
allowedOrigins:
|
||||
- "https://*.example.com" # CORS allowed origins
|
||||
|
||||
auth:
|
||||
cookieDomain: ".example.com" # Cookie domain for SSO
|
||||
allowedEmails:
|
||||
- "admin@example.com" # Allowed user emails
|
||||
|
||||
secrets:
|
||||
sessionSecret: "your-secure-random-secret" # Session signing secret
|
||||
|
||||
ingress:
|
||||
hosts:
|
||||
- host: auth.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
```
|
||||
|
||||
|
||||
## Setup Authentication for Your Services
|
||||
|
||||
Add these annotations to your ingress resources to protect them with passkey authentication:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: my-protected-app
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/auth"
|
||||
nginx.ingress.kubernetes.io/auth-signin: "https://auth.example.com/login?rd=$scheme://$http_host$request_uri"
|
||||
nginx.ingress.kubernetes.io/auth-response-headers: "X-Auth-User,X-Auth-Email"
|
||||
spec:
|
||||
# ... your ingress spec
|
||||
```
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom Storage
|
||||
|
||||
```yaml
|
||||
persistence:
|
||||
enabled: true
|
||||
existingClaim: "my-existing-pvc"
|
||||
storageClass: "ssd-encrypted"
|
||||
size: 10Gi
|
||||
```
|
||||
|
||||
### External Secrets
|
||||
|
||||
```yaml
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: external-secrets
|
||||
|
||||
secrets: {} # Don't create internal secret
|
||||
```
|
||||
|
||||
|
||||
## Parameters
|
||||
|
||||
### Common parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
| ------------------- | ---------------------------------------------------------------------------------------- | ----- |
|
||||
| `nameOverride` | String to partially override passkey-auth.fullname template | `""` |
|
||||
| `fullnameOverride` | String to fully override passkey-auth.fullname template | `""` |
|
||||
| `commonLabels` | Add labels to all the deployed resources | `{}` |
|
||||
| `commonAnnotations` | Add annotations to all the deployed resources | `{}` |
|
||||
|
||||
### Passkey Auth parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
| ----------------------------- | --------------------------------------------------------------- | ---------------------------------- |
|
||||
| `replicaCount` | Number of Passkey Auth replicas to deploy | `1` |
|
||||
| `image.repository` | Passkey Auth image repository | `ghcr.io/wahyd4/passkey-auth` |
|
||||
| `image.tag` | Passkey Auth image tag (immutable tags are recommended) | `main` |
|
||||
| `image.pullPolicy` | Passkey Auth image pull policy | `Always` |
|
||||
| `image.pullSecrets` | Passkey Auth image pull secrets | `[]` |
|
||||
|
||||
### WebAuthn configuration
|
||||
|
||||
| Name | Description | Value |
|
||||
| --------------------------------- | --------------------------------------------------------------- | ------------------------------ |
|
||||
| `config.webauthn.rpDisplayName` | WebAuthn Relying Party display name | `Passkey Auth` |
|
||||
| `config.webauthn.rpId` | WebAuthn Relying Party ID (must match your domain) | `pass.example.com` |
|
||||
| `config.webauthn.rpOrigins` | Allowed origins for WebAuthn (array) | `["https://pass.example.com"]` |
|
||||
|
||||
### CORS configuration
|
||||
|
||||
| Name | Description | Value |
|
||||
| --------------------------------- | --------------------------------------------------------------- | -------------------------------- |
|
||||
| `config.cors.allowedOrigins` | CORS allowed origins (array) | `["https://*.example.com"]` |
|
||||
|
||||
### Authentication configuration
|
||||
|
||||
| Name | Description | Value |
|
||||
| --------------------------------- | --------------------------------------------------------------- | ------------------------------ |
|
||||
| `config.auth.requireApproval` | Require admin approval for new user registrations | `true` |
|
||||
| `config.auth.cookieDomain` | Cookie domain for SSO (e.g., .example.com) | `.example.com` |
|
||||
| `config.auth.allowedEmails` | List of allowed email addresses (array) | `["admin@example.com"]` |
|
||||
| `config.auth.allowedDomains` | List of allowed email domains (array) | `[]` |
|
||||
|
||||
### Service configuration
|
||||
|
||||
| Name | Description | Value |
|
||||
| -------------- | ----------------------------------- | ----------- |
|
||||
| `service.type` | Kubernetes service type | `ClusterIP` |
|
||||
| `service.port` | Kubernetes service port | `80` |
|
||||
|
||||
### Ingress configuration
|
||||
|
||||
| Name | Description | Value |
|
||||
| -------------------------- | --------------------------------------------------------------- | ------------------------------ |
|
||||
| `ingress.enabled` | Enable ingress controller resource | `true` |
|
||||
| `ingress.className` | IngressClass that will be used to implement the Ingress | `nginx` |
|
||||
| `ingress.annotations` | Additional annotations for the Ingress resource | `{}` |
|
||||
| `ingress.hosts[0].host` | Hostname for the ingress | `pass.example.com` |
|
||||
| `ingress.hosts[0].paths` | Paths for the ingress | `[{path: "/", pathType: "Prefix"}]` |
|
||||
| `ingress.tls` | TLS configuration for ingress | `[]` |
|
||||
|
||||
### Persistence configuration
|
||||
|
||||
| Name | Description | Value |
|
||||
| ----------------------------- | --------------------------------------------------------------- | ------------------ |
|
||||
| `persistence.enabled` | Enable persistent volume for data storage | `true` |
|
||||
| `persistence.storageClass` | Persistent Volume storage class | `""` |
|
||||
| `persistence.accessMode` | Persistent Volume access mode | `ReadWriteOnce` |
|
||||
| `persistence.size` | Persistent Volume size | `2Gi` |
|
||||
| `persistence.existingClaim` | Use existing persistent volume claim | `""` |
|
||||
|
||||
### Security configuration
|
||||
|
||||
| Name | Description | Value |
|
||||
| ------------------------------------------------- | --------------------------------------------------------------- | ---------------------------------------------- |
|
||||
| `secrets.sessionSecret` | Session secret for signing cookies (change in production!) | `change-me-in-production-use-long-random-string` |
|
||||
| `podSecurityContext.fsGroup` | Group ID for the pods | `1000` |
|
||||
| `securityContext.allowPrivilegeEscalation` | Allow privilege escalation for containers | `false` |
|
||||
| `securityContext.runAsNonRoot` | Run containers as non-root user | `true` |
|
||||
| `securityContext.runAsUser` | User ID for the containers | `1000` |
|
||||
| `securityContext.capabilities.drop` | Dropped capabilities | `["ALL"]` |
|
||||
|
||||
### Resource management
|
||||
|
||||
| Name | Description | Value |
|
||||
| ----------------------------- | --------------------------------------------------------------- | -------- |
|
||||
| `resources.limits.cpu` | CPU resource limits | `400m` |
|
||||
| `resources.limits.memory` | Memory resource limits | `512Mi` |
|
||||
| `resources.requests.cpu` | CPU resource requests | `100m` |
|
||||
| `resources.requests.memory` | Memory resource requests | `128Mi` |
|
||||
|
||||
### Autoscaling configuration
|
||||
|
||||
| Name | Description | Value |
|
||||
| -------------------------------------------------- | --------------------------------------------------------------- | ------- |
|
||||
| `autoscaling.enabled` | Enable Horizontal Pod Autoscaler | `false` |
|
||||
| `autoscaling.minReplicas` | Minimum number of replicas | `1` |
|
||||
| `autoscaling.maxReplicas` | Maximum number of replicas | `3` |
|
||||
| `autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization percentage | `80` |
|
||||
| `autoscaling.targetMemoryUtilizationPercentage` | Target memory utilization percentage | `""` |
|
||||
|
||||
### Environment variables
|
||||
|
||||
| Name | Description | Value |
|
||||
| ---------------- | --------------------------------------------------------------- | ------- |
|
||||
| `env.CONFIG_PATH` | Path to the configuration file | `/app/config.yaml` |
|
||||
| `env.ADMIN_EMAIL` | Admin email for auto-approval (optional) | `""` |
|
||||
| `env.DEFAULT_EMAIL` | Default email for initial setup (optional) | `""` |
|
||||
|
||||
### Other parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
| ------------- | --------------------------------------------------------------- | ------- |
|
||||
| `nodeSelector` | Node labels for pod assignment | `{}` |
|
||||
| `tolerations` | Tolerations for pod assignment | `[]` |
|
||||
| `affinity` | Affinity for pod assignment | `{}` |
|
||||
@@ -0,0 +1,62 @@
|
||||
# Development values for passkey-auth
|
||||
# Use this for local development and testing
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: ghcr.io/wahyd4/passkey-auth
|
||||
tag: "main"
|
||||
pullPolicy: Always
|
||||
|
||||
# Application configuration
|
||||
config:
|
||||
webauthn:
|
||||
rpDisplayName: "Dev Passkey Auth"
|
||||
rpId: "localhost"
|
||||
rpOrigins:
|
||||
- "http://localhost:8080"
|
||||
- "https://auth.dev.local"
|
||||
|
||||
cors:
|
||||
allowedOrigins:
|
||||
- "*" # Allow all origins in dev
|
||||
|
||||
auth:
|
||||
requireApproval: false # Auto-approve in dev
|
||||
cookieDomain: ".dev.local"
|
||||
allowedEmails: [] # Allow any email in dev
|
||||
|
||||
# Security configuration (dev only)
|
||||
secrets:
|
||||
sessionSecret: "dev-secret-not-for-production"
|
||||
|
||||
# Disable ingress for local development
|
||||
ingress:
|
||||
enabled: false
|
||||
|
||||
# Minimal persistence for dev
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 1Gi
|
||||
|
||||
# Minimal resources for dev
|
||||
resources:
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
# Disable autoscaling
|
||||
autoscaling:
|
||||
enabled: false
|
||||
|
||||
# Environment variables
|
||||
env:
|
||||
- name: DEFAULT_EMAIL
|
||||
value: "dev@example.com"
|
||||
- name: CONFIG_PATH
|
||||
value: "/app/config.yaml"
|
||||
- name: ADMIN_EMAIL
|
||||
value: "dev@example.com"
|
||||
@@ -0,0 +1,117 @@
|
||||
# Production values for passkey-auth
|
||||
# Use this as a template for production deployments
|
||||
|
||||
replicaCount: 2
|
||||
|
||||
image:
|
||||
repository: ghcr.io/wahyd4/passkey-auth
|
||||
tag: "v1.0.0" # Pin to specific version in production
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# Application configuration
|
||||
config:
|
||||
webauthn:
|
||||
rpDisplayName: "My Company Passkey Auth"
|
||||
rpId: "auth.company.com" # CHANGE THIS
|
||||
rpOrigins:
|
||||
- "https://auth.company.com" # CHANGE THIS
|
||||
|
||||
cors:
|
||||
allowedOrigins:
|
||||
- "https://*.company.com" # CHANGE THIS
|
||||
- "https://app.company.com" # Add specific origins
|
||||
|
||||
auth:
|
||||
requireApproval: true
|
||||
cookieDomain: ".company.com" # CHANGE THIS
|
||||
allowedEmails:
|
||||
- "admin@company.com" # CHANGE THIS
|
||||
- "user@company.com" # Add allowed users
|
||||
|
||||
# Security configuration
|
||||
secrets:
|
||||
sessionSecret: "" # REQUIRED: Set this to a secure random string (32+ chars)
|
||||
|
||||
# Ingress configuration
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "nginx"
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
hosts:
|
||||
- host: auth.company.com # CHANGE THIS
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: auth-company-com-tls
|
||||
hosts:
|
||||
- auth.company.com # CHANGE THIS
|
||||
|
||||
# Persistence configuration
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: "fast-ssd" # Use fast storage for production
|
||||
size: 5Gi
|
||||
accessMode: ReadWriteOnce
|
||||
|
||||
# Resource configuration
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
|
||||
# Autoscaling configuration
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 2
|
||||
maxReplicas: 5
|
||||
targetCPUUtilizationPercentage: 70
|
||||
|
||||
# Health checks
|
||||
healthCheck:
|
||||
enabled: true
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
# Security context
|
||||
podSecurityContext:
|
||||
fsGroup: 1000
|
||||
runAsNonRoot: true
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: false # SQLite needs write access
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
|
||||
# Node selection
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
|
||||
# Environment variables
|
||||
env:
|
||||
- name: DEFAULT_EMAIL
|
||||
value: "admin@company.com" # CHANGE THIS
|
||||
- name: CONFIG_PATH
|
||||
value: "/app/config.yaml"
|
||||
- name: ADMIN_EMAIL
|
||||
value: "admin@company.com" # CHANGE THIS
|
||||
@@ -0,0 +1,40 @@
|
||||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "passkey-auth.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "passkey-auth.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "passkey-auth.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "passkey-auth.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||
{{- end }}
|
||||
|
||||
2. Configure your ingress for authentication by adding these annotations to your protected services:
|
||||
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/auth-url: "http{{ if .Values.ingress.tls }}s{{ end }}://{{ (index .Values.ingress.hosts 0).host }}/auth"
|
||||
nginx.ingress.kubernetes.io/auth-signin: "http{{ if .Values.ingress.tls }}s{{ end }}://{{ (index .Values.ingress.hosts 0).host }}/login?rd=$scheme://$http_host$request_uri"
|
||||
nginx.ingress.kubernetes.io/auth-response-headers: "X-Auth-User,X-Auth-Email"
|
||||
|
||||
3. Visit the admin panel to manage users:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
http{{ if .Values.ingress.tls }}s{{ end }}://{{ (index .Values.ingress.hosts 0).host }}/admin
|
||||
{{- end }}
|
||||
|
||||
Important Security Notes:
|
||||
- Change the default session secret in values.yaml before deploying to production
|
||||
- Configure proper CORS origins for your domain
|
||||
- Set up proper TLS certificates
|
||||
- Review and configure allowed email addresses
|
||||
@@ -0,0 +1,87 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "passkey-auth.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "passkey-auth.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "passkey-auth.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "passkey-auth.labels" -}}
|
||||
helm.sh/chart: {{ include "passkey-auth.chart" . }}
|
||||
{{ include "passkey-auth.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "passkey-auth.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "passkey-auth.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "passkey-auth.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "passkey-auth.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the configmap
|
||||
*/}}
|
||||
{{- define "passkey-auth.configmapName" -}}
|
||||
{{- printf "%s-config" (include "passkey-auth.fullname" .) }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the secret
|
||||
*/}}
|
||||
{{- define "passkey-auth.secretName" -}}
|
||||
{{- printf "%s-secrets" (include "passkey-auth.fullname" .) }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the PVC
|
||||
*/}}
|
||||
{{- define "passkey-auth.pvcName" -}}
|
||||
{{- if .Values.persistence.existingClaim }}
|
||||
{{- .Values.persistence.existingClaim }}
|
||||
{{- else }}
|
||||
{{- printf "%s-pvc" (include "passkey-auth.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,38 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "passkey-auth.configmapName" . }}
|
||||
labels:
|
||||
{{- include "passkey-auth.labels" . | nindent 4 }}
|
||||
data:
|
||||
config.yaml: |
|
||||
server:
|
||||
port: {{ .Values.config.server.port | quote }}
|
||||
host: {{ .Values.config.server.host | quote }}
|
||||
|
||||
webauthn:
|
||||
rp_display_name: {{ .Values.config.webauthn.rpDisplayName | quote }}
|
||||
rp_id: {{ .Values.config.webauthn.rpId | quote }}
|
||||
rp_origins:
|
||||
{{- range .Values.config.webauthn.rpOrigins }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
|
||||
database:
|
||||
path: {{ .Values.config.database.path | quote }}
|
||||
|
||||
cors:
|
||||
allowed_origins:
|
||||
{{- range .Values.config.cors.allowedOrigins }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
|
||||
auth:
|
||||
require_approval: {{ .Values.config.auth.requireApproval }}
|
||||
cookie_domain: {{ .Values.config.auth.cookieDomain | quote }}
|
||||
{{- if .Values.config.auth.allowedEmails }}
|
||||
allowed_emails:
|
||||
{{- range .Values.config.auth.allowedEmails }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,121 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "passkey-auth.fullname" . }}
|
||||
labels:
|
||||
{{- include "passkey-auth.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- end }}
|
||||
revisionHistoryLimit: 3
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "passkey-auth.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "passkey-auth.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "passkey-auth.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.targetPort }}
|
||||
protocol: TCP
|
||||
env:
|
||||
{{- range .Values.env }}
|
||||
- name: {{ .name }}
|
||||
value: {{ .value | quote }}
|
||||
{{- end }}
|
||||
- name: SESSION_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "passkey-auth.secretName" . }}
|
||||
key: session-secret
|
||||
{{- with .Values.envFrom }}
|
||||
envFrom:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: "/app/config.yaml"
|
||||
subPath: config.yaml
|
||||
readOnly: true
|
||||
{{- if .Values.persistence.enabled }}
|
||||
- name: data
|
||||
mountPath: /data
|
||||
{{- end }}
|
||||
{{- with .Values.volumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.healthCheck.enabled }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: {{ .Values.healthCheck.path }}
|
||||
port: http
|
||||
initialDelaySeconds: {{ .Values.healthCheck.livenessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.healthCheck.livenessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ .Values.healthCheck.livenessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ .Values.healthCheck.livenessProbe.failureThreshold }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: {{ .Values.healthCheck.path }}
|
||||
port: http
|
||||
initialDelaySeconds: {{ .Values.healthCheck.readinessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.healthCheck.readinessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ .Values.healthCheck.readinessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ .Values.healthCheck.readinessProbe.failureThreshold }}
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: {{ .Values.healthCheck.path }}
|
||||
port: http
|
||||
initialDelaySeconds: {{ .Values.healthCheck.startupProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.healthCheck.startupProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ .Values.healthCheck.startupProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ .Values.healthCheck.startupProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ include "passkey-auth.configmapName" . }}
|
||||
{{- if .Values.persistence.enabled }}
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "passkey-auth.pvcName" . }}
|
||||
{{- end }}
|
||||
{{- with .Values.volumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
restartPolicy: Always
|
||||
@@ -0,0 +1,32 @@
|
||||
{{- if .Values.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "passkey-auth.fullname" . }}
|
||||
labels:
|
||||
{{- include "passkey-auth.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "passkey-auth.fullname" . }}
|
||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,56 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "passkey-auth.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
{{- if and .Values.ingress.className (not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class")) }}
|
||||
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
|
||||
{{- end }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{- include "passkey-auth.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- if not (hasKey . "nginx.ingress.kubernetes.io/upstream-vhost") }}
|
||||
nginx.ingress.kubernetes.io/upstream-vhost: {{ $.Values.config.webauthn.rpId | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
|
||||
pathType: {{ .pathType }}
|
||||
{{- end }}
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ $fullName }}
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- else }}
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $svcPort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,20 @@
|
||||
{{- if .Values.persistence.enabled }}
|
||||
{{- if not .Values.persistence.existingClaim }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "passkey-auth.pvcName" . }}
|
||||
labels:
|
||||
{{- include "passkey-auth.labels" . | nindent 4 }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.persistence.accessMode }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.size }}
|
||||
{{- if .Values.persistence.storageClass }}
|
||||
storageClassName: {{ .Values.persistence.storageClass }}
|
||||
{{- end }}
|
||||
volumeMode: Filesystem
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "passkey-auth.secretName" . }}
|
||||
labels:
|
||||
{{- include "passkey-auth.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
session-secret: {{ .Values.secrets.sessionSecret | b64enc | quote }}
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "passkey-auth.fullname" . }}
|
||||
labels:
|
||||
{{- include "passkey-auth.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "passkey-auth.selectorLabels" . | nindent 4 }}
|
||||
@@ -0,0 +1,12 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "passkey-auth.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "passkey-auth.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,165 @@
|
||||
# Default values for passkey-auth.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: ghcr.io/wahyd4/passkey-auth
|
||||
pullPolicy: Always
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: "main"
|
||||
|
||||
imagePullSecrets:
|
||||
- name: github-image-pull-secret
|
||||
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: false
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
podAnnotations: {}
|
||||
|
||||
podSecurityContext:
|
||||
fsGroup: 1000
|
||||
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "nginx"
|
||||
annotations:
|
||||
kubernetes.io/tls-acme: "true"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/proxy-set-headers: "passkey-auth-headers"
|
||||
nginx.ingress.kubernetes.io/upstream-vhost: "" # Will be set to config.webauthn.rpId
|
||||
nginx.ingress.kubernetes.io/proxy-redirect-from: "http://"
|
||||
nginx.ingress.kubernetes.io/proxy-redirect-to: "https://"
|
||||
hosts:
|
||||
- host: pass.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: passkey-auth-tls
|
||||
hosts:
|
||||
- pass.example.com
|
||||
|
||||
resources:
|
||||
limits:
|
||||
cpu: 400m
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 3
|
||||
targetCPUUtilizationPercentage: 80
|
||||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
# Persistent storage for SQLite database
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: "" # Use default storage class
|
||||
accessMode: ReadWriteOnce
|
||||
size: 2Gi
|
||||
# existingClaim: ""
|
||||
|
||||
# Health check configuration
|
||||
healthCheck:
|
||||
enabled: true
|
||||
path: /health
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
startupProbe:
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 6
|
||||
|
||||
# Application configuration
|
||||
config:
|
||||
server:
|
||||
port: "8080"
|
||||
host: "0.0.0.0"
|
||||
|
||||
webauthn:
|
||||
rpDisplayName: "Passkey Auth"
|
||||
rpId: "pass.example.com"
|
||||
rpOrigins:
|
||||
- "https://pass.example.com"
|
||||
|
||||
database:
|
||||
path: "/data/passkey-auth.db"
|
||||
|
||||
cors:
|
||||
allowedOrigins:
|
||||
- "https://*.example.com"
|
||||
|
||||
auth:
|
||||
requireApproval: true
|
||||
cookieDomain: ".example.com"
|
||||
allowedEmails:
|
||||
- "admin@example.com"
|
||||
# adminEmail will be set via environment variable
|
||||
|
||||
# Environment variables
|
||||
env:
|
||||
- name: DEFAULT_EMAIL
|
||||
value: "admin@example.com"
|
||||
- name: CONFIG_PATH
|
||||
value: "/app/config.yaml"
|
||||
- name: ADMIN_EMAIL
|
||||
value: "admin@example.com"
|
||||
|
||||
# Secret environment variables
|
||||
secrets:
|
||||
# Session secret for cookie signing
|
||||
sessionSecret: "change-me-in-production-use-long-random-string"
|
||||
|
||||
# Additional environment variables from existing secrets
|
||||
envFrom: []
|
||||
# - secretRef:
|
||||
# name: my-secret
|
||||
|
||||
# Additional volume mounts
|
||||
volumeMounts: []
|
||||
|
||||
# Additional volumes
|
||||
volumes: []
|
||||
Executable
BIN
Binary file not shown.
Executable
+128
@@ -0,0 +1,128 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Helm Chart Validation Script
|
||||
# This script validates the Helm chart before deployment
|
||||
|
||||
set -e
|
||||
|
||||
CHART_DIR="helm/passkey-auth"
|
||||
NAMESPACE="passkey-auth-test"
|
||||
|
||||
echo "🔍 Validating Passkey Auth Helm Chart..."
|
||||
|
||||
# Check if helm is installed
|
||||
if ! command -v helm &> /dev/null; then
|
||||
echo "❌ Helm is not installed. Please install Helm first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if kubectl is installed
|
||||
if ! command -v kubectl &> /dev/null; then
|
||||
echo "❌ kubectl is not installed. Please install kubectl first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Prerequisites check passed"
|
||||
|
||||
# Lint the chart
|
||||
echo "🔧 Linting Helm chart..."
|
||||
if helm lint $CHART_DIR; then
|
||||
echo "✅ Chart linting passed"
|
||||
else
|
||||
echo "❌ Chart linting failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Template the chart with test values
|
||||
echo "📝 Templating chart with test values..."
|
||||
helm template test-release $CHART_DIR \
|
||||
--set config.webauthn.rpId=test.example.com \
|
||||
--set config.webauthn.rpOrigins="{https://test.example.com}" \
|
||||
--set config.cors.allowedOrigins="{https://test.example.com}" \
|
||||
--set config.auth.cookieDomain=".example.com" \
|
||||
--set config.auth.allowedEmails="{admin@example.com}" \
|
||||
--set secrets.sessionSecret="test-secret-for-validation-only" \
|
||||
--set ingress.hosts[0].host=test.example.com \
|
||||
--set ingress.tls[0].hosts="{test.example.com}" \
|
||||
> /tmp/passkey-auth-template.yaml
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Chart templating passed"
|
||||
else
|
||||
echo "❌ Chart templating failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate Kubernetes manifests
|
||||
echo "🔍 Validating Kubernetes manifests..."
|
||||
if kubectl apply --dry-run=client -f /tmp/passkey-auth-template.yaml; then
|
||||
echo "✅ Kubernetes manifest validation passed"
|
||||
else
|
||||
echo "❌ Kubernetes manifest validation failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for required values
|
||||
echo "🔧 Checking for required configuration..."
|
||||
|
||||
REQUIRED_VALUES=(
|
||||
"config.webauthn.rpId"
|
||||
"config.webauthn.rpOrigins"
|
||||
"secrets.sessionSecret"
|
||||
)
|
||||
|
||||
for value in "${REQUIRED_VALUES[@]}"; do
|
||||
if helm template test-release $CHART_DIR --show-only templates/configmap.yaml | grep -q "REQUIRED"; then
|
||||
echo "❌ Required value not set: $value"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "✅ Required values check passed"
|
||||
|
||||
# Test with production values
|
||||
if [ -f "$CHART_DIR/examples/values-production.yaml" ]; then
|
||||
echo "🏭 Testing with production values..."
|
||||
helm template test-release $CHART_DIR \
|
||||
-f $CHART_DIR/examples/values-production.yaml \
|
||||
--set secrets.sessionSecret="test-secret" \
|
||||
> /tmp/passkey-auth-production.yaml
|
||||
|
||||
if kubectl apply --dry-run=client -f /tmp/passkey-auth-production.yaml; then
|
||||
echo "✅ Production values validation passed"
|
||||
else
|
||||
echo "❌ Production values validation failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Test with development values
|
||||
if [ -f "$CHART_DIR/examples/values-development.yaml" ]; then
|
||||
echo "🚀 Testing with development values..."
|
||||
helm template test-release $CHART_DIR \
|
||||
-f $CHART_DIR/examples/values-development.yaml \
|
||||
> /tmp/passkey-auth-development.yaml
|
||||
|
||||
if kubectl apply --dry-run=client -f /tmp/passkey-auth-development.yaml; then
|
||||
echo "✅ Development values validation passed"
|
||||
else
|
||||
echo "❌ Development values validation failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm -f /tmp/passkey-auth-*.yaml
|
||||
|
||||
echo "🎉 All validations passed! The Helm chart is ready for deployment."
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Update values in values.yaml or use --set flags"
|
||||
echo "2. Install the chart: helm install my-passkey-auth $CHART_DIR"
|
||||
echo "3. Configure your ingress controllers to use the auth backend"
|
||||
echo ""
|
||||
echo "For production deployment, make sure to:"
|
||||
echo "• Set a secure session secret"
|
||||
echo "• Configure proper domains and origins"
|
||||
echo "• Set up TLS certificates"
|
||||
echo "• Configure allowed email addresses"
|
||||
Reference in New Issue
Block a user