diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100644 index 0000000..b9c7d48 --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,36 @@ +style: github +template: | + ## {{ if .PreviousTag }}[{{ .Version }}]({{ .Info.RepositoryURL }}/compare/{{ .PreviousTag }}...{{ .Version }}){{ else }}{{ .Version }}{{ end }} - {{ .Info.Date.Format "2006-01-02" }} + + {{ range .Commits -}} + {{- if or (contains .Commit.Header "feat") (contains .Commit.Header "fix") (contains .Commit.Header "docs") }} + {{- if or (contains .Commit.Header "refactor") (contains .Commit.Header "perf") (contains .Commit.Header "test") }} + {{- if or (contains .Commit.Header "build") (contains .Commit.Header "ci") (contains .Commit.Header "chore") }} + * {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} + {{ end -}}{{ end -}}{{ end -}} + {{ end }} + +info: + title: CHANGELOG + repository_url: https://github.com/wikodit/charts +options: + commit_filters: + Type: + - feat + - fix + - docs + - refactor + - perf + - test + - build + - ci + - chore + header: + pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?!?: (.*)$" + maps: + - Type: 1 + - Scope: 2 + - Subject: 3 + notes: + keywords: + - BREAKING CHANGE diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 009c2fe..4cfe670 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -20,7 +20,7 @@ ## Checklist -- [ ] Chart version bumped in `Chart.yaml` +- [ ] Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) format - [ ] `helm lint` passes - [ ] `helm template` renders correctly - [ ] Unit tests pass (if applicable) diff --git a/.github/workflows/lint-test.yaml b/.github/workflows/lint-test.yaml index 9e92ef5..0a66a14 100644 --- a/.github/workflows/lint-test.yaml +++ b/.github/workflows/lint-test.yaml @@ -35,7 +35,7 @@ jobs: - name: Set up Helm uses: azure/setup-helm@v4 with: - version: v3.16.3 + version: v3.19.4 - name: Set up Python uses: actions/setup-python@v5 @@ -68,34 +68,56 @@ jobs: runs-on: ubuntu-latest needs: lint if: needs.lint.outputs.changed == 'true' + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Helm uses: azure/setup-helm@v4 with: - version: v3.16.3 + version: v3.19.4 - - name: Cache Helm plugins - uses: actions/cache@v4 - with: - path: ~/.local/share/helm/plugins - key: helm-plugins-unittest-${{ runner.os }} + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.7.0 - - name: Install helm-unittest plugin + - name: Get changed charts + id: set-matrix run: | - if ! helm plugin list | grep -q unittest; then - helm plugin install https://github.com/helm-unittest/helm-unittest.git + # Use main as target branch for push events + TARGET_BRANCH="main" + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + TARGET_BRANCH="${{ github.base_ref }}" + fi + + changed=$(ct list-changed --config ct.yaml --target-branch $TARGET_BRANCH 2>/dev/null || echo "") + if [[ -z "$changed" ]]; then + # Fallback: check git diff + changed=$(git diff --name-only origin/$TARGET_BRANCH HEAD -- charts/ 2>/dev/null | grep -oP 'charts/\K[^/]+' | sort -u || echo "") fi + if [[ -n "$changed" ]]; then + CHARTS=$(echo "$changed" | jq -R -s -c 'split("\n") | map(select(. != ""))') + else + CHARTS='[]' + fi + + echo "matrix={\"chart\":$CHARTS}" >> "$GITHUB_OUTPUT" + + - name: Install helm-unittest plugin + run: | + helm plugin install https://github.com/helm-unittest/helm-unittest.git + - name: Run unit tests run: | failed=0 - for chart in charts/*/; do - if [[ -d "${chart}tests" ]]; then - echo "Testing ${chart}" - if ! helm unittest "${chart}"; then + for chart in ${{ fromJson(needs.lint.outputs.charts) }}; do + if [[ -d "charts/${chart}/tests" ]]; then + echo "Testing charts/${chart}" + if ! helm unittest "charts/${chart}"; then failed=1 fi fi @@ -113,7 +135,7 @@ jobs: - name: Set up Helm uses: azure/setup-helm@v4 with: - version: v3.16.3 + version: v3.19.4 - name: Install kubeconform run: | @@ -123,18 +145,18 @@ jobs: - name: Validate manifests run: | failed=0 - for chart in charts/*/; do - chart_name=$(basename "$chart") - echo "Validating ${chart_name}" + for chart in ${{ fromJson(needs.lint.outputs.charts) }}; do + chart_path="charts/${chart}" + echo "Validating ${chart}" # Use ci values if available, otherwise default values_file="" - if [[ -f "${chart}ci/default-values.yaml" ]]; then - values_file="-f ${chart}ci/default-values.yaml" + if [[ -f "${chart_path}ci/default-values.yaml" ]]; then + values_file="-f ${chart_path}ci/default-values.yaml" fi - helm dependency update "$chart" 2>/dev/null || true - if ! helm template "$chart" $values_file | kubeconform -strict -summary -output json; then + helm dependency update "$chart_path" 2>/dev/null || true + if ! helm template "$chart_path" $values_file | kubeconform -strict -summary -output json; then failed=1 fi echo "::endgroup::" @@ -145,6 +167,9 @@ jobs: runs-on: ubuntu-latest needs: lint if: needs.lint.outputs.changed == 'true' + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.lint.outputs.charts) }} steps: - name: Checkout uses: actions/checkout@v4 @@ -153,7 +178,7 @@ jobs: uses: aquasecurity/trivy-action@0.28.0 with: scan-type: 'fs' - scan-ref: 'charts/' + scan-ref: 'charts/${{ matrix.chart }}' scanners: 'misconfig' format: 'table' exit-code: '1' @@ -173,7 +198,7 @@ jobs: - name: Set up Helm uses: azure/setup-helm@v4 with: - version: v3.16.3 + version: v3.19.4 - name: Set up chart-testing uses: helm/chart-testing-action@v2.7.0 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 2fab607..361df59 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,7 +20,7 @@ on: concurrency: group: release-${{ github.ref }} - cancel-in-progress: false + cancel-in-progress: 'false' env: GHCR_REGISTRY: ghcr.io @@ -41,7 +41,7 @@ jobs: - name: Set up Helm uses: azure/setup-helm@v4 with: - version: v3.16.3 + version: v3.19.4 - name: Set up chart-testing uses: helm/chart-testing-action@v2.7.0 @@ -98,11 +98,14 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} - name: Set up Helm uses: azure/setup-helm@v4 with: - version: v3.16.3 + version: v3.19.4 - name: Install cosign uses: sigstore/cosign-installer@v3.7.0 @@ -110,6 +113,89 @@ jobs: - name: Install yq uses: mikefarah/yq@v4 + - name: Determine version bump from conventional commits + id: version-bump + run: | + CHART_PATH="charts/${{ matrix.chart }}" + CHART_NAME=$(yq '.name' "${CHART_PATH}/Chart.yaml") + + # Get the last release tag for this chart + LAST_TAG=$(git tag --list "${CHART_NAME}-v*" --sort=-version:refname | head -n1 || echo "") + + if [[ -z "$LAST_TAG" ]]; then + # No previous release, get all commits for this chart + echo "No previous release found for ${CHART_NAME}" + COMMITS=$(git log --oneline --no-merges -- "${CHART_PATH}") + CURRENT_VERSION="0.0.0" + else + echo "Last release: ${LAST_TAG}" + COMMITS=$(git log --oneline --no-merges "${LAST_TAG}..HEAD" -- "${CHART_PATH}") + # Extract version from tag (chart-name-vX.Y.Z -> X.Y.Z) + CURRENT_VERSION=$(echo "$LAST_TAG" | sed "s/${CHART_NAME}-v//") + fi + + echo "Current version: ${CURRENT_VERSION}" + echo "Commits since last release:" + echo "$COMMITS" + + # Determine bump type from conventional commits + BUMP_TYPE="none" + + # Check for breaking changes (BREAKING CHANGE in body or ! after type) + if echo "$COMMITS" | grep -qiE '(BREAKING CHANGE|^[a-z]+!:|!)'; then + BUMP_TYPE="major" + # Check for features + elif echo "$COMMITS" | grep -qiE '^[a-f0-9]+ feat'; then + BUMP_TYPE="minor" + # Check for fixes or any other changes + elif echo "$COMMITS" | grep -qiE '^[a-f0-9]+ (fix|perf|refactor|docs|style|test|chore|ci|build)'; then + BUMP_TYPE="patch" + elif [[ -n "$COMMITS" ]]; then + # Any other commits default to patch + BUMP_TYPE="patch" + fi + + echo "Bump type: ${BUMP_TYPE}" + + if [[ "$BUMP_TYPE" == "none" ]]; then + echo "::error::No commits found since last release. Nothing to bump." + exit 1 + fi + + # Calculate new version + IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION" + + case "$BUMP_TYPE" in + major) + NEW_VERSION="$((MAJOR + 1)).0.0" + ;; + minor) + NEW_VERSION="${MAJOR}.$((MINOR + 1)).0" + ;; + patch) + NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" + ;; + esac + + echo "New version: ${NEW_VERSION}" + + echo "bump_type=${BUMP_TYPE}" >> "$GITHUB_OUTPUT" + echo "current_version=${CURRENT_VERSION}" >> "$GITHUB_OUTPUT" + echo "new_version=${NEW_VERSION}" >> "$GITHUB_OUTPUT" + + - name: Update Chart.yaml version + id: update-version + run: | + CHART_PATH="charts/${{ matrix.chart }}" + NEW_VERSION="${{ steps.version-bump.outputs.new_version }}" + + # Update version and appVersion in Chart.yaml + yq -i ".version = \"${NEW_VERSION}\"" "${CHART_PATH}/Chart.yaml" + yq -i ".appVersion = \"${NEW_VERSION}\"" "${CHART_PATH}/Chart.yaml" + + echo "Updated Chart.yaml to version ${NEW_VERSION}" + cat "${CHART_PATH}/Chart.yaml" + - name: Get chart info id: chart-info run: | @@ -154,6 +240,48 @@ jobs: run: | helm dependency update "${{ steps.chart-info.outputs.path }}" || true + - name: Generate CHANGELOG + run: | + # Install git-chglog + wget -O git-chglog.tar.gz https://github.com/git-chglog/git-chglog/releases/latest/download/git-chglog_linux_amd64.tar.gz + tar xzf git-chglog.tar.gz + sudo mv git-chglog /usr/local/bin/ + + # Generate changelog for this chart + CHANGELOG_PATH="${{ steps.chart-info.outputs.path }}/CHANGELOG.md" + + # Get previous tag for this chart + PREV_TAG=$(git tag --list "${{ steps.chart-info.outputs.name }}-*" --sort=-version:refname | sed -n '2p' || echo "") + + if [[ -f "$CHANGELOG_PATH" ]]; then + # Backup existing changelog + cp "$CHANGELOG_PATH" "$CHANGELOG_PATH.bak" + fi + + # Generate new changelog entry + if [[ -n "$PREV_TAG" ]]; then + git-chglog --config .chglog/config.yml --output "$CHANGELOG_PATH" "$PREV_TAG..HEAD" --path "${{ steps.chart-info.outputs.path }}" + else + git-chglog --config .chglog/config.yml --output "$CHANGELOG_PATH" --path "${{ steps.chart-info.outputs.path }}" + fi + + # If backup exists, prepend new entries to it + if [[ -f "$CHANGELOG_PATH.bak" ]]; then + echo "# Changelog" > temp_changelog + echo "" >> temp_changelog + cat "$CHANGELOG_PATH" >> temp_changelog + echo "" >> temp_changelog + tail -n +2 "$CHANGELOG_PATH.bak" >> temp_changelog + mv temp_changelog "$CHANGELOG_PATH" + rm "$CHANGELOG_PATH.bak" + else + # Add header if this is a new changelog + { echo "# Changelog"; echo ""; cat "$CHANGELOG_PATH"; } > temp_changelog + mv temp_changelog "$CHANGELOG_PATH" + fi + + echo "Generated CHANGELOG for ${{ steps.chart-info.outputs.name }}" + - name: Package chart run: | mkdir -p .packaged @@ -279,6 +407,33 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Commit CHANGELOG + if: success() + run: | + # Configure git + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + + # Add Chart.yaml (version bump) and CHANGELOG + git add "${{ steps.chart-info.outputs.path }}/Chart.yaml" + git add "${{ steps.chart-info.outputs.path }}/CHANGELOG.md" + + # Check if there are changes to commit + if git diff --staged --quiet; then + echo "No changes to commit" + else + git commit -m "chore(${{ steps.chart-info.outputs.name }}): release v${{ steps.chart-info.outputs.version }} [skip ci]" \ + -m "Bump version from ${{ steps.version-bump.outputs.current_version }} to ${{ steps.version-bump.outputs.new_version }}" \ + -m "Update CHANGELOG.md" + + # Pull latest changes to avoid conflicts + git pull --rebase origin main + + # Push changes + git push https://github-actions:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git main + echo "Version bump and CHANGELOG committed and pushed" + fi + - name: Summary run: | cat >> "$GITHUB_STEP_SUMMARY" < minor bump +fix: resolve bug # -> patch bump +docs: update readme # -> patch bump +feat!: breaking change # -> major bump +BREAKING CHANGE: description # -> major bump +``` ## Pull Request Process diff --git a/charts/wik-webservice/README.md.gotmpl b/charts/wik-webservice/README.md.gotmpl index 4c77076..d9588f1 100644 --- a/charts/wik-webservice/README.md.gotmpl +++ b/charts/wik-webservice/README.md.gotmpl @@ -10,7 +10,7 @@ This chart simplifies the deployment of a webservice on Kubernetes. It creates: - **ConfigMap/Secret/SealedSecret** for environment variables -- **Secret/SealedSecret** for docker pull credentials +- **Secret/SealedSecret** for registry pull credentials - **Deployment** with configurable containers, probes, and resources - **Service** with optional metrics port and Prometheus annotations - **Ingress** with configurable hosts and annotations @@ -71,13 +71,115 @@ helm install my-app ./wik-webservice -f values.yaml | `webservice.resources` | CPU/Memory requests and limits | `{}` | | `webservice.livenessProbe` | Liveness probe configuration | `{}` | | `webservice.readinessProbe` | Readiness probe configuration | `{}` | +| `webservice.startupProbe` | Startup probe configuration | `{}` | ### Security | Parameter | Description | Default | |-----------|-------------|---------| +| `serviceAccount.create` | Create a dedicated ServiceAccount | `false` | +| `serviceAccount.name` | ServiceAccount name to use | `""` (default) | +| `serviceAccount.annotations` | ServiceAccount annotations | `{}` | +| `serviceAccount.automountServiceAccountToken` | Mount service account token (when creating SA) | `true` | | `webservice.securityContext` | Pod-level security context | `{}` | | `webservice.containerSecurityContext` | Container-level security context | `{}` | +| `webservice.enableServiceLinks` | Enable service links injection | `false` | +| `webservice.hostNetwork` | Access host network namespace | `false` | +| `webservice.hostPID` | Access host PID namespace | `false` | +| `webservice.hostIPC` | Access host IPC namespace | `false` | + +#### ServiceAccount Configuration + +By default, pods use the default ServiceAccount with `automountServiceAccountToken: false` for security. This prevents the token from being mounted in the pod unless explicitly needed. + +```yaml +# Default behavior (no token mounted) +# Uses default ServiceAccount, token is not mounted + +# Create dedicated ServiceAccount with token +serviceAccount: + create: true + automountServiceAccountToken: true + +# Use existing ServiceAccount +serviceAccount: + create: false + name: "existing-sa" + +# Create ServiceAccount with IAM role (EKS example) +serviceAccount: + create: true + annotations: + eks.amazonaws.com/role-arn: "arn:aws:iam::123456789012:role/my-role" + automountServiceAccountToken: true +``` + +#### Service Links + +Service links inject all cluster services as environment variables in the pod. This is disabled by default for security to reduce information leakage. + +```yaml +# Default (service links disabled) +webservice: + enableServiceLinks: false + +# Enable service links if needed +webservice: + enableServiceLinks: true +``` + +#### Host Protection + +Host protection settings prevent pods from accessing host resources: + +```yaml +# Default (all host protections disabled) +webservice: + hostNetwork: false + hostPID: false + hostIPC: false + +# Enable host network access (rarely needed) +webservice: + hostNetwork: true + # Note: This allows the pod to access the host's network interface +``` + +**Warning**: Enabling host access (hostNetwork, hostPID, hostIPC) significantly reduces isolation and should only be used when absolutely necessary. + +### Image Security + +For production deployments, follow these image security best practices: + +```yaml +# Use specific image digests for immutability +webservice: + image: "nginx@sha256:abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890" + imagePullPolicy: IfNotPresent + +# Use private registry with authentication +webservice: + image: "private-registry.com/myapp:v1.2.3" + imagePullAuth: + registry: "private-registry.com" + username: "deploy-user" + password: "secure-password" + +# Use SealedSecrets for encrypted credentials +general: + sealedSecrets: true +webservice: + imagePullAuth: + registry: "private-registry.com" + encrypted: "AgBy3i4OJSWK+PiTySYZZA9rO43cGDEQAx..." +``` + +**Image Security Recommendations:** +- Use specific image digests instead of tags for production +- Prefer `imagePullPolicy: IfNotPresent` for pinned images +- Store registry credentials in encrypted secrets +- Regularly scan images for vulnerabilities +- Use minimal base images to reduce attack surface ### Environment Variables @@ -93,14 +195,244 @@ helm install my-app ./wik-webservice -f values.yaml | `webservice.storage` | PVC definitions | `{}` | | `webservice.volumes` | Volume mounts (PVC, ConfigMap, Secret) | `[]` | +### Observability + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `webservice.metrics.enabled` | Enable metrics endpoint | `false` | +| `webservice.metrics.port` | Metrics port | `9090` | +| `webservice.metrics.path` | Metrics path | `/metrics` | +| `serviceMonitor.enabled` | Enable ServiceMonitor | `false` | +| `serviceMonitor.interval` | Scrape interval | `30s` | +| `serviceMonitor.scrapeTimeout` | Scrape timeout | `10s` | +| `serviceMonitor.honorLabels` | Honor labels | `false` | +| `serviceMonitor.additionalLabels` | Additional labels | `{}` | +| `horizontalPodAutoscaler.enabled` | Enable HPA | `false` | +| `horizontalPodAutoscaler.minReplicas` | Minimum replicas | `1` | +| `horizontalPodAutoscaler.maxReplicas` | Maximum replicas | `5` | +| `horizontalPodAutoscaler.targetCPUUtilizationPercentage` | CPU target | `80` | +| `horizontalPodAutoscaler.targetMemoryUtilizationPercentage` | Memory target | `null` | +| `runtimeClassName` | Runtime class for isolation | `""` (default) | +| `podSecurityStandard.enabled` | Enable Pod Security Standards | `true` | +| `podSecurityStandard.level` | Security level | `restricted` | + +#### Metrics and Monitoring + +The chart supports Prometheus metrics collection through ServiceMonitor: + +```yaml +# Enable metrics endpoint +webservice: + metrics: + enabled: true + port: 9090 + path: /metrics + +# Enable ServiceMonitor for Prometheus +serviceMonitor: + enabled: true + interval: 30s + scrapeTimeout: 10s + additionalLabels: + release: prometheus + +# Custom metric relabeling +serviceMonitor: + enabled: true + metricRelabelings: + - sourceLabels: [__name__] + regex: 'http_.*' + action: drop +``` + +#### Horizontal Pod Autoscaling + +The chart supports automatic scaling based on CPU and memory usage: + +```yaml +# Enable HPA with CPU target +horizontalPodAutoscaler: + enabled: true + minReplicas: 2 + maxReplicas: 10 + targetCPUUtilizationPercentage: 70 + +# Enable HPA with both CPU and memory targets +horizontalPodAutoscaler: + enabled: true + minReplicas: 1 + maxReplicas: 20 + targetCPUUtilizationPercentage: 60 + targetMemoryUtilizationPercentage: 70 + +# Custom scaling behavior +horizontalPodAutoscaler: + enabled: true + behavior: + scaleUp: + stabilizationWindowSeconds: 60 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 10 + periodSeconds: 60 +``` + +#### Runtime Class + +Runtime class allows using alternative container runtimes for stronger isolation: + +```yaml +# Use gVisor for user-space kernel isolation +runtimeClassName: "gvisor" + +# Use Kata Containers for VM-level isolation +runtimeClassName: "kata" + +# Default (regular container runtime) +runtimeClassName: "" +``` + +**Note**: Runtime classes must be installed on the cluster before use. gVisor and Kata provide stronger isolation but may have performance overhead. + +#### Pod Security Standards + +Pod Security Standards (PSS) replace Pod Security Policies in Kubernetes 1.25+. They enforce security policies at the namespace level: + +```yaml +# Enable restricted security level (default) +podSecurityStandard: + enabled: true + level: restricted + +# Use baseline for less strict requirements +podSecurityStandard: + enabled: true + level: baseline + +# Disable Pod Security Standards +podSecurityStandard: + enabled: false +``` + +**Security Levels:** +- **restricted**: Most secure - non-root, read-only FS, no privileged, resource limits required +- **baseline**: Medium security - prevents obvious security issues +- **privileged**: No restrictions - not recommended for production + ### Scheduling | Parameter | Description | Default | |-----------|-------------|---------| +| `podDisruptionBudget.enabled` | Enable PodDisruptionBudget | `false` | +| `podDisruptionBudget.minAvailable` | Minimum available pods | `1` | +| `podDisruptionBudget.maxUnavailable` | Maximum unavailable pods | `""` | +| `networkPolicy.enabled` | Enable NetworkPolicy | `false` | +| `networkPolicy.ingress` | Custom ingress rules | `[]` | +| `networkPolicy.egress` | Custom egress rules | `[]` | +| `webservice.topologySpreadConstraints` | Pod distribution constraints | `[]` | | `webservice.nodeSelector` | Node selector | `{}` | | `webservice.affinity` | Affinity rules | `{}` | | `webservice.strategy` | Deployment strategy | `{}` | +#### PodDisruptionBudget + +PodDisruptionBudget ensures application availability during voluntary disruptions (node maintenance, cluster upgrades): + +```yaml +# Ensure at least 1 pod is always available +podDisruptionBudget: + enabled: true + minAvailable: 1 + +# Allow at most 1 pod to be unavailable (good for multi-replica deployments) +podDisruptionBudget: + enabled: true + maxUnavailable: 1 + +# Percentage-based availability +podDisruptionBudget: + enabled: true + minAvailable: "50%" +``` + +#### NetworkPolicy + +NetworkPolicy restricts network traffic to/from pods. By default, it allows traffic from the ingress-nginx namespace: + +```yaml +# Enable with default rules (allow ingress traffic only) +networkPolicy: + enabled: true + +# Custom ingress rules +networkPolicy: + enabled: true + ingress: + - from: + - podSelector: + matchLabels: + app: frontend + ports: + - protocol: TCP + port: 80 + +# Restrict egress to specific services +networkPolicy: + enabled: true + egress: + - to: + - podSelector: + matchLabels: + app: database + ports: + - protocol: TCP + port: 5432 +``` + +#### TopologySpreadConstraints + +TopologySpreadConstraints control how pods are spread across your cluster to improve high availability: + +```yaml +# Spread pods across different nodes +webservice: + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + app.kubernetes.io/name: wik-webservice + app.kubernetes.io/instance: release-name + +# Spread pods across availability zones +webservice: + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: topology.kubernetes.io/zone + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + app.kubernetes.io/name: wik-webservice + app.kubernetes.io/instance: release-name + +# Multiple constraints for better distribution +webservice: + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + - maxSkew: 1 + topologyKey: topology.kubernetes.io/zone + whenUnsatisfiable: ScheduleAnyway +``` + ### Additional Containers | Parameter | Description | Default | @@ -108,6 +440,76 @@ helm install my-app ./wik-webservice -f values.yaml | `webservice.initContainers` | Init containers | `[]` | | `webservice.additionalContainers` | Sidecar containers | `[]` | +## Security & Resource Defaults + +This chart includes secure defaults that can be overridden as needed: + +### Security Context Defaults + +By default, pods run with the following security settings: + +```yaml +# Pod Security Context +securityContext: + fsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + +# Container Security Context +securityContext: + runAsNonRoot: true + runAsUser: 1000 + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + +To override these defaults, set `webservice.securityContext` or `webservice.containerSecurityContext`: + +```yaml +webservice: + securityContext: + runAsUser: 2000 + fsGroup: 2000 + containerSecurityContext: + readOnlyRootFilesystem: false + seccompProfile: + type: Localhost + localhostProfile: "profiles/custom.json" +``` + +### Resource Defaults + +If no resources are specified, the following defaults are applied: + +```yaml +resources: + requests: + cpu: 100m + memory: 128Mi + ephemeral-storage: 1Gi + limits: + cpu: 500m + memory: 512Mi + ephemeral-storage: 2Gi +``` + +To customize resources: + +```yaml +webservice: + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 1000m + memory: 1Gi +``` + ## Examples ### Basic deployment @@ -144,6 +546,13 @@ webservice: httpGet: path: /ready port: 80 + startupProbe: + httpGet: + path: /startup + port: 80 + initialDelaySeconds: 10 + periodSeconds: 10 + failureThreshold: 30 ``` ### With metrics enabled diff --git a/charts/wik-webservice/ci/default-values.yaml b/charts/wik-webservice/ci/default-values.yaml index 7f58060..2609eea 100644 --- a/charts/wik-webservice/ci/default-values.yaml +++ b/charts/wik-webservice/ci/default-values.yaml @@ -1,6 +1,18 @@ webservice: - image: nginx:latest + image: nginxinc/nginx-unprivileged:latest hosts: - test.example.com replicas: 1 - port: 80 + port: 8080 + + # nginx needs writable dirs when using readOnlyRootFilesystem + volumes: + - name: nginx-cache + mountPath: /var/cache/nginx + emptyDir: {} + - name: nginx-run + mountPath: /var/run + emptyDir: {} + - name: nginx-tmp + mountPath: /tmp + emptyDir: {} diff --git a/charts/wik-webservice/ci/full-values.yaml b/charts/wik-webservice/ci/full-values.yaml index a47a777..ef28ba0 100644 --- a/charts/wik-webservice/ci/full-values.yaml +++ b/charts/wik-webservice/ci/full-values.yaml @@ -2,10 +2,10 @@ general: sealedSecrets: false webservice: - image: nginx:latest + image: nginxinc/nginx-unprivileged:latest imagePullPolicy: Always replicas: 2 - port: 80 + port: 8080 hosts: - test.example.com - api.example.com @@ -53,15 +53,15 @@ webservice: livenessProbe: httpGet: - path: /health - port: 80 + path: / + port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: - path: /ready - port: 80 + path: / + port: 8080 initialDelaySeconds: 5 periodSeconds: 5 @@ -76,20 +76,33 @@ webservice: affinity: nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - eu-west-1a - storage: - data: - size: 10Gi - storageClass: standard - volumes: - name: data mountPath: /app/data - storage: true + storage: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: standard + + # nginx needs writable dirs when using readOnlyRootFilesystem + - name: nginx-cache + mountPath: /var/cache/nginx + emptyDir: {} + - name: nginx-run + mountPath: /var/run + emptyDir: {} + - name: nginx-tmp + mountPath: /tmp + emptyDir: {} diff --git a/charts/wik-webservice/requirements.yaml b/charts/wik-webservice/requirements.yaml deleted file mode 100644 index 32cf5dd..0000000 --- a/charts/wik-webservice/requirements.yaml +++ /dev/null @@ -1 +0,0 @@ -dependencies: [] diff --git a/charts/wik-webservice/templates/_helpers.tpl b/charts/wik-webservice/templates/_helpers.tpl index b37613e..9f212dd 100644 --- a/charts/wik-webservice/templates/_helpers.tpl +++ b/charts/wik-webservice/templates/_helpers.tpl @@ -16,4 +16,30 @@ {{- else }} {{- template "fullname" .root }} {{- end }} -{{- end -}} \ No newline at end of file +{{- end -}} + +{{- define "serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{- define "labels" -}} +helm.sh/chart: {{ include "chart" . }} +{{ include "selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{- define "selectorLabels" -}} +app.kubernetes.io/name: {{ include "name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{- define "chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/charts/wik-webservice/templates/deployment.yaml b/charts/wik-webservice/templates/deployment.yaml index 9ed586a..3883e56 100644 --- a/charts/wik-webservice/templates/deployment.yaml +++ b/charts/wik-webservice/templates/deployment.yaml @@ -6,8 +6,13 @@ metadata: labels: app: {{ template "name" . }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - heritage: {{ .Release.Service }} release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{ if .Values.podSecurityStandard.enabled }} + pod-security.kubernetes.io/enforce: {{ .Values.podSecurityStandard.level }} + pod-security.kubernetes.io/audit: {{ .Values.podSecurityStandard.level }} + pod-security.kubernetes.io/warn: {{ .Values.podSecurityStandard.level }} +{{ end }} spec: replicas: {{ .Values.webservice.replicas }} revisionHistoryLimit: {{ .Values.webservice.revisionHistoryLimit }} @@ -15,6 +20,10 @@ spec: matchLabels: app: {{ template "name" . }} release: {{ .Release.Name }} +{{ if .Values.webservice.topologySpreadConstraints }} + topologySpreadConstraints: +{{ .Values.webservice.topologySpreadConstraints | toYaml | indent 4 }} +{{ end }} {{ if .Values.webservice.strategy }} strategy: {{ .Values.webservice.strategy | toYaml | indent 4 }} @@ -34,14 +43,29 @@ spec: {{ .Values.webservice.annotations | toYaml | indent 8 }} {{ end }} spec: +{{ if .Values.serviceAccount.create }} + serviceAccountName: {{ include "serviceAccountName" . }} +{{ end }} + automountServiceAccountToken: false + enableServiceLinks: {{ .Values.webservice.enableServiceLinks }} + hostNetwork: {{ .Values.webservice.hostNetwork }} + hostPID: {{ .Values.webservice.hostPID }} + hostIPC: {{ .Values.webservice.hostIPC }} +{{ if .Values.runtimeClassName }} + runtimeClassName: {{ .Values.runtimeClassName }} +{{ end }} {{ if .Values.webservice.hostAliases }} hostAliases: {{ .Values.webservice.hostAliases | toYaml | indent 8 }} {{ end }} -{{ if .Values.webservice.securityContext }} securityContext: +{{- if .Values.webservice.securityContext }} {{ .Values.webservice.securityContext | toYaml | indent 8 }} -{{ end }} +{{- else }} + fsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 +{{- end }} {{ if .Values.webservice.dnsConfig }} dnsConfig: {{ .Values.webservice.dnsConfig | toYaml | indent 8 }} @@ -52,10 +76,20 @@ spec: containers: - name: {{ template "fullname" . }} image: {{ .Values.webservice.image }} -{{ if .Values.webservice.containerSecurityContext}} securityContext: +{{- if .Values.webservice.containerSecurityContext }} {{ .Values.webservice.containerSecurityContext | toYaml | indent 12 }} -{{ end }} +{{- else }} + runAsNonRoot: true + runAsUser: 1000 + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault +{{- end }} imagePullPolicy: {{ .Values.webservice.imagePullPolicy }} ports: - name: http @@ -86,7 +120,18 @@ spec: {{ end }} resources: +{{- if .Values.webservice.resources }} {{ .Values.webservice.resources | toYaml | indent 12 }} +{{- else }} + limits: + cpu: 500m + memory: 512Mi + ephemeral-storage: 2Gi + requests: + cpu: 100m + memory: 128Mi + ephemeral-storage: 1Gi +{{- end }} {{ if .Values.webservice.livenessProbe }} livenessProbe: {{ .Values.webservice.livenessProbe | toYaml | indent 12 }} @@ -95,6 +140,10 @@ spec: readinessProbe: {{ .Values.webservice.readinessProbe | toYaml | indent 12 }} {{ end }} +{{ if .Values.webservice.startupProbe }} + startupProbe: +{{ .Values.webservice.startupProbe | toYaml | indent 12 }} +{{ end }} {{ if .Values.webservice.volumes }} volumeMounts: {{ range .Values.webservice.volumes }} @@ -159,7 +208,7 @@ spec: {{ if .Values.webservice.imagePullAuth }} imagePullSecrets: - - name: {{ template "fullname" . }}-docker + - name: {{ template "fullname" . }}-registry {{ end }} {{ if .Values.webservice.volumes }} @@ -185,6 +234,11 @@ spec: optional: {{ .secret.optional }} {{ end }} +{{ if hasKey . "emptyDir" }} + - name: {{ .name }} + emptyDir: {{ if eq (len .emptyDir) 0 }}{}{{ else }}{{ .emptyDir | toJson }}{{ end }} +{{ end }} + {{ end }} {{ end }} diff --git a/charts/wik-webservice/templates/hpa.yaml b/charts/wik-webservice/templates/hpa.yaml new file mode 100644 index 0000000..f16d397 --- /dev/null +++ b/charts/wik-webservice/templates/hpa.yaml @@ -0,0 +1,43 @@ +{{- if .Values.horizontalPodAutoscaler.enabled -}} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "fullname" . }} + labels: + {{- include "labels" . | nindent 4 }} + {{- with .Values.horizontalPodAutoscaler.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "fullname" . }} + minReplicas: {{ .Values.horizontalPodAutoscaler.minReplicas }} + maxReplicas: {{ .Values.horizontalPodAutoscaler.maxReplicas }} + metrics: + {{- if .Values.horizontalPodAutoscaler.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.horizontalPodAutoscaler.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.horizontalPodAutoscaler.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.horizontalPodAutoscaler.targetMemoryUtilizationPercentage }} + {{- end }} + {{- with .Values.horizontalPodAutoscaler.customMetrics }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.horizontalPodAutoscaler.behavior }} + behavior: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/wik-webservice/templates/ingress.yaml b/charts/wik-webservice/templates/ingress.yaml index b7c70bc..6701405 100644 --- a/charts/wik-webservice/templates/ingress.yaml +++ b/charts/wik-webservice/templates/ingress.yaml @@ -43,7 +43,7 @@ spec: service: name: {{ template "fullname" $root }} port: - number: 80 + number: {{ $root.Values.webservice.service.port | default $root.Values.webservice.port | default 80 }} pathType: Prefix path: / {{ end }} diff --git a/charts/wik-webservice/templates/networkpolicy.yaml b/charts/wik-webservice/templates/networkpolicy.yaml new file mode 100644 index 0000000..8b03499 --- /dev/null +++ b/charts/wik-webservice/templates/networkpolicy.yaml @@ -0,0 +1,39 @@ +{{- if .Values.networkPolicy.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "fullname" . }} + labels: + {{- include "labels" . | nindent 4 }} + {{- with .Values.networkPolicy.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + {{- if .Values.networkPolicy.ingress }} + ingress: + {{- toYaml .Values.networkPolicy.ingress | nindent 4 }} + {{- else }} + ingress: + - from: + - namespaceSelector: + matchLabels: + name: ingress-nginx + ports: + - protocol: TCP + port: {{ .Values.webservice.port }} + {{- end }} + {{- if .Values.networkPolicy.egress }} + egress: + {{- toYaml .Values.networkPolicy.egress | nindent 4 }} + {{- else }} + egress: + - {} + {{- end }} +{{- end }} diff --git a/charts/wik-webservice/templates/poddisruptionbudget.yaml b/charts/wik-webservice/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..b10cbeb --- /dev/null +++ b/charts/wik-webservice/templates/poddisruptionbudget.yaml @@ -0,0 +1,22 @@ +{{- if .Values.podDisruptionBudget.enabled -}} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "fullname" . }} + labels: + {{- include "labels" . | nindent 4 }} + {{- with .Values.podDisruptionBudget.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: + {{- include "selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/charts/wik-webservice/templates/docker-secret.yaml b/charts/wik-webservice/templates/registry-secret.yaml similarity index 93% rename from charts/wik-webservice/templates/docker-secret.yaml rename to charts/wik-webservice/templates/registry-secret.yaml index d6cdfb9..445e923 100644 --- a/charts/wik-webservice/templates/docker-secret.yaml +++ b/charts/wik-webservice/templates/registry-secret.yaml @@ -7,7 +7,7 @@ apiVersion: bitnami.com/v1alpha1 kind: SealedSecret metadata: - name: "{{ template "fullname" . }}-docker" + name: "{{ template "fullname" . }}-registry" labels: app: {{ template "name" . }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" @@ -28,7 +28,7 @@ apiVersion: v1 kind: Secret type: kubernetes.io/dockerconfigjson metadata: - name: "{{ template "fullname" . }}-docker" + name: "{{ template "fullname" . }}-registry" labels: app: {{ template "name" . }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" diff --git a/charts/wik-webservice/templates/serviceaccount.yaml b/charts/wik-webservice/templates/serviceaccount.yaml new file mode 100644 index 0000000..7a08db2 --- /dev/null +++ b/charts/wik-webservice/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "serviceAccountName" . }} + labels: + {{- include "labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/charts/wik-webservice/templates/servicemonitor.yaml b/charts/wik-webservice/templates/servicemonitor.yaml new file mode 100644 index 0000000..5282537 --- /dev/null +++ b/charts/wik-webservice/templates/servicemonitor.yaml @@ -0,0 +1,42 @@ +{{- if and .Values.webservice.metrics.enabled .Values.serviceMonitor.enabled -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "fullname" . }} + labels: + {{- include "labels" . | nindent 4 }} + {{- with .Values.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.serviceMonitor.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "selectorLabels" . | nindent 6 }} + {{- if .Values.webservice.service.metricsPort }} + metrics-port: {{ .Values.webservice.service.metricsPort | quote }} + {{- end }} + endpoints: + - port: {{ default "metrics" .Values.webservice.service.metricsPort }} + {{- if .Values.serviceMonitor.interval }} + interval: {{ .Values.serviceMonitor.interval }} + {{- end }} + {{- if .Values.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }} + {{- end }} + {{- if .Values.serviceMonitor.honorLabels }} + honorLabels: {{ .Values.serviceMonitor.honorLabels }} + {{- end }} + path: {{ default "/metrics" .Values.webservice.metrics.path }} + {{- if .Values.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.serviceMonitor.metricRelabelings | nindent 8 }} + {{- end }} + {{- if .Values.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.serviceMonitor.relabelings | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/wik-webservice/tests/enableservicelinks_test.yaml b/charts/wik-webservice/tests/enableservicelinks_test.yaml new file mode 100644 index 0000000..7a47af7 --- /dev/null +++ b/charts/wik-webservice/tests/enableservicelinks_test.yaml @@ -0,0 +1,30 @@ +suite: enable service links tests +templates: + - deployment.yaml +tests: + - it: should set enableServiceLinks to false by default + set: + webservice: + image: nginx:latest + asserts: + - equal: + path: spec.template.spec.enableServiceLinks + value: false + - it: should allow enabling service links when set to true + set: + webservice: + image: nginx:latest + enableServiceLinks: true + asserts: + - equal: + path: spec.template.spec.enableServiceLinks + value: true + - it: should allow disabling service links explicitly + set: + webservice: + image: nginx:latest + enableServiceLinks: false + asserts: + - equal: + path: spec.template.spec.enableServiceLinks + value: false diff --git a/charts/wik-webservice/tests/ephemeralstorage_test.yaml b/charts/wik-webservice/tests/ephemeralstorage_test.yaml new file mode 100644 index 0000000..0134731 --- /dev/null +++ b/charts/wik-webservice/tests/ephemeralstorage_test.yaml @@ -0,0 +1,44 @@ +suite: ephemeral storage tests +templates: + - deployment.yaml +tests: + - it: should add ephemeral storage limits by default + set: + webservice: + image: nginx:latest + asserts: + - equal: + path: spec.template.spec.containers[0].resources.requests.ephemeral-storage + value: "1Gi" + - equal: + path: spec.template.spec.containers[0].resources.limits.ephemeral-storage + value: "2Gi" + - it: should allow custom ephemeral storage limits + set: + webservice: + image: nginx:latest + resources: + requests: + ephemeral-storage: "5Gi" + limits: + ephemeral-storage: "10Gi" + asserts: + - equal: + path: spec.template.spec.containers[0].resources.requests.ephemeral-storage + value: "5Gi" + - equal: + path: spec.template.spec.containers[0].resources.limits.ephemeral-storage + value: "10Gi" + - it: should allow only setting requests or limits + set: + webservice: + image: nginx:latest + resources: + requests: + ephemeral-storage: "2Gi" + asserts: + - equal: + path: spec.template.spec.containers[0].resources.requests.ephemeral-storage + value: "2Gi" + - notExists: + path: spec.template.spec.containers[0].resources.limits.ephemeral-storage diff --git a/charts/wik-webservice/tests/hostprotection_test.yaml b/charts/wik-webservice/tests/hostprotection_test.yaml new file mode 100644 index 0000000..fae46ed --- /dev/null +++ b/charts/wik-webservice/tests/hostprotection_test.yaml @@ -0,0 +1,63 @@ +suite: host protection tests +templates: + - deployment.yaml +tests: + - it: should set host protection to false by default + set: + webservice: + image: nginx:latest + asserts: + - equal: + path: spec.template.spec.hostNetwork + value: false + - equal: + path: spec.template.spec.hostPID + value: false + - equal: + path: spec.template.spec.hostIPC + value: false + - it: should allow enabling hostNetwork when needed + set: + webservice: + image: nginx:latest + hostNetwork: true + asserts: + - equal: + path: spec.template.spec.hostNetwork + value: true + - equal: + path: spec.template.spec.hostPID + value: false + - equal: + path: spec.template.spec.hostIPC + value: false + - it: should allow enabling hostPID when needed + set: + webservice: + image: nginx:latest + hostPID: true + asserts: + - equal: + path: spec.template.spec.hostNetwork + value: false + - equal: + path: spec.template.spec.hostPID + value: true + - equal: + path: spec.template.spec.hostIPC + value: false + - it: should allow enabling hostIPC when needed + set: + webservice: + image: nginx:latest + hostIPC: true + asserts: + - equal: + path: spec.template.spec.hostNetwork + value: false + - equal: + path: spec.template.spec.hostPID + value: false + - equal: + path: spec.template.spec.hostIPC + value: true diff --git a/charts/wik-webservice/tests/hpa_test.yaml b/charts/wik-webservice/tests/hpa_test.yaml new file mode 100644 index 0000000..c183966 --- /dev/null +++ b/charts/wik-webservice/tests/hpa_test.yaml @@ -0,0 +1,90 @@ +suite: horizontal pod autoscaler tests +templates: + - hpa.yaml +tests: + - it: should create an HPA when enabled with CPU target + set: + webservice: + image: nginx:latest + horizontalPodAutoscaler: + enabled: true + minReplicas: 2 + maxReplicas: 10 + targetCPUUtilizationPercentage: 70 + asserts: + - containsDocument: + kind: HorizontalPodAutoscaler + apiVersion: autoscaling/v2 + name: "release-name-wik-webservice" + - equal: + path: spec.minReplicas + value: 2 + - equal: + path: spec.maxReplicas + value: 10 + - equal: + path: spec.metrics[0].resource.name + value: "cpu" + - equal: + path: spec.metrics[0].resource.target.averageUtilization + value: 70 + - it: should not create an HPA when disabled + set: + webservice: + image: nginx:latest + horizontalPodAutoscaler: + enabled: false + asserts: + - notContainsDocument: + kind: HorizontalPodAutoscaler + apiVersion: autoscaling/v2 + - it: should create an HPA with both CPU and memory targets + set: + webservice: + image: nginx:latest + horizontalPodAutoscaler: + enabled: true + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 60 + asserts: + - equal: + path: spec.metrics[0].resource.name + value: "cpu" + - equal: + path: spec.metrics[1].resource.name + value: "memory" + - equal: + path: spec.metrics[1].resource.target.averageUtilization + value: 60 + - it: should include annotations when provided + set: + webservice: + image: nginx:latest + horizontalPodAutoscaler: + enabled: true + annotations: + autoscaling.alpha.kubernetes.io/conditions: "true" + asserts: + - equal: + path: metadata.annotations."autoscaling.alpha.kubernetes.io/conditions" + value: "true" + - it: should include custom behavior when provided + set: + webservice: + image: nginx:latest + horizontalPodAutoscaler: + enabled: true + behavior: + scaleUp: + stabilizationWindowSeconds: 60 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + asserts: + - equal: + path: spec.behavior.scaleUp.stabilizationWindowSeconds + value: 60 + - equal: + path: spec.behavior.scaleUp.policies[0].value + value: 100 diff --git a/charts/wik-webservice/tests/networkpolicy_test.yaml b/charts/wik-webservice/tests/networkpolicy_test.yaml new file mode 100644 index 0000000..e54198a --- /dev/null +++ b/charts/wik-webservice/tests/networkpolicy_test.yaml @@ -0,0 +1,88 @@ +suite: network policy tests +templates: + - networkpolicy.yaml +tests: + - it: should create a NetworkPolicy when enabled + set: + webservice: + image: nginx:latest + port: 80 + networkPolicy: + enabled: true + asserts: + - containsDocument: + kind: NetworkPolicy + apiVersion: networking.k8s.io/v1 + name: "release-name-wik-webservice" + - equal: + path: spec.policyTypes + value: + - Ingress + - Egress + - equal: + path: spec.podSelector.matchLabels."app.kubernetes.io/name" + value: "wik-webservice" + - it: should not create a NetworkPolicy when disabled + set: + webservice: + image: nginx:latest + networkPolicy: + enabled: false + asserts: + - notContainsDocument: + kind: NetworkPolicy + apiVersion: networking.k8s.io/v1 + - it: should use default ingress when not specified + set: + webservice: + image: nginx:latest + port: 8080 + networkPolicy: + enabled: true + asserts: + - equal: + path: spec.ingress[0].from[0].namespaceSelector.matchLabels.name + value: "ingress-nginx" + - equal: + path: spec.ingress[0].ports[0].port + value: 8080 + - it: should use custom ingress rules when specified + set: + webservice: + image: nginx:latest + port: 80 + networkPolicy: + enabled: true + ingress: + - from: + - podSelector: + matchLabels: + app: frontend + ports: + - protocol: TCP + port: 80 + asserts: + - equal: + path: spec.ingress[0].from[0].podSelector.matchLabels.app + value: "frontend" + - it: should use custom egress rules when specified + set: + webservice: + image: nginx:latest + networkPolicy: + enabled: true + egress: + - to: + - podSelector: + matchLabels: + app: database + ports: + - protocol: TCP + port: 5432 + asserts: + - equal: + path: spec.egress[0].to[0].podSelector.matchLabels.app + value: "database" + - equal: + path: spec.egress[0].ports[0].port + value: 5432 diff --git a/charts/wik-webservice/tests/poddisruptionbudget_test.yaml b/charts/wik-webservice/tests/poddisruptionbudget_test.yaml new file mode 100644 index 0000000..76c53e4 --- /dev/null +++ b/charts/wik-webservice/tests/poddisruptionbudget_test.yaml @@ -0,0 +1,59 @@ +suite: pod disruption budget tests +templates: + - poddisruptionbudget.yaml +tests: + - it: should create a PDB when enabled with minAvailable + set: + webservice: + image: nginx:latest + podDisruptionBudget: + enabled: true + minAvailable: 1 + asserts: + - containsDocument: + kind: PodDisruptionBudget + apiVersion: policy/v1 + name: "release-name-wik-webservice" + - equal: + path: spec.minAvailable + value: 1 + - equal: + path: spec.selector.matchLabels."app.kubernetes.io/name" + value: "wik-webservice" + - it: should create a PDB when enabled with maxUnavailable + set: + webservice: + image: nginx:latest + podDisruptionBudget: + enabled: true + maxUnavailable: 1 + asserts: + - containsDocument: + kind: PodDisruptionBudget + apiVersion: policy/v1 + - equal: + path: spec.maxUnavailable + value: 1 + - it: should not create a PDB when disabled + set: + webservice: + image: nginx:latest + podDisruptionBudget: + enabled: false + asserts: + - notContainsDocument: + kind: PodDisruptionBudget + apiVersion: policy/v1 + - it: should include annotations when provided + set: + webservice: + image: nginx:latest + podDisruptionBudget: + enabled: true + minAvailable: 1 + annotations: + example.com/annotation: "test" + asserts: + - equal: + path: metadata.annotations."example.com/annotation" + value: "test" diff --git a/charts/wik-webservice/tests/podsecuritystandard_test.yaml b/charts/wik-webservice/tests/podsecuritystandard_test.yaml new file mode 100644 index 0000000..6cdb128 --- /dev/null +++ b/charts/wik-webservice/tests/podsecuritystandard_test.yaml @@ -0,0 +1,62 @@ +suite: pod security standard tests +templates: + - deployment.yaml +tests: + - it: should add Pod Security Standard labels when enabled + set: + webservice: + image: nginx:latest + podSecurityStandard: + enabled: true + level: restricted + asserts: + - equal: + path: metadata.labels."pod-security.kubernetes.io/enforce" + value: "restricted" + - equal: + path: metadata.labels."pod-security.kubernetes.io/audit" + value: "restricted" + - equal: + path: metadata.labels."pod-security.kubernetes.io/warn" + value: "restricted" + - it: should not add Pod Security Standard labels when disabled + set: + webservice: + image: nginx:latest + podSecurityStandard: + enabled: false + asserts: + - notExists: + path: metadata.labels."pod-security.kubernetes.io/enforce" + - notExists: + path: metadata.labels."pod-security.kubernetes.io/audit" + - notExists: + path: metadata.labels."pod-security.kubernetes.io/warn" + - it: should support baseline security level + set: + webservice: + image: nginx:latest + podSecurityStandard: + enabled: true + level: baseline + asserts: + - equal: + path: metadata.labels."pod-security.kubernetes.io/enforce" + value: "baseline" + - equal: + path: metadata.labels."pod-security.kubernetes.io/audit" + value: "baseline" + - equal: + path: metadata.labels."pod-security.kubernetes.io/warn" + value: "baseline" + - it: should support privileged security level + set: + webservice: + image: nginx:latest + podSecurityStandard: + enabled: true + level: privileged + asserts: + - equal: + path: metadata.labels."pod-security.kubernetes.io/enforce" + value: "privileged" diff --git a/charts/wik-webservice/tests/docker-secret_test.yaml b/charts/wik-webservice/tests/registry-secret_test.yaml similarity index 68% rename from charts/wik-webservice/tests/docker-secret_test.yaml rename to charts/wik-webservice/tests/registry-secret_test.yaml index 94658d7..f383bbf 100644 --- a/charts/wik-webservice/tests/docker-secret_test.yaml +++ b/charts/wik-webservice/tests/registry-secret_test.yaml @@ -1,24 +1,27 @@ suite: docker secret tests templates: - docker-secret.yaml + - deployment.yaml tests: - it: should create a docker registry secret when imagePullAuth is provided set: webservice: image: nginx:latest imagePullAuth: - registry: registry.example.com - username: myuser - password: mypass + registry: "my-registry.com" + username: "user" + password: "pass" asserts: - - isKind: - of: Secret + - containsDocument: + kind: Secret + apiVersion: v1 + name: "release-name-wik-webservice-registry" + - equal: + path: metadata.name + value: "release-name-wik-webservice-registry" - equal: path: type value: kubernetes.io/dockerconfigjson - - equal: - path: metadata.name - value: release-name-wik-webservice-registry - exists: path: data.".dockerconfigjson" @@ -28,8 +31,12 @@ tests: image: nginx:latest imagePullAuth: {} asserts: - - hasDocuments: - count: 0 + - notContainsDocument: + kind: Secret + apiVersion: v1 + - notContainsDocument: + kind: SealedSecret + apiVersion: bitnami.com/v1alpha1 - it: should include encrypted value when sealedSecrets is enabled set: diff --git a/charts/wik-webservice/tests/runtimeclassname_test.yaml b/charts/wik-webservice/tests/runtimeclassname_test.yaml new file mode 100644 index 0000000..b1c5209 --- /dev/null +++ b/charts/wik-webservice/tests/runtimeclassname_test.yaml @@ -0,0 +1,43 @@ +suite: runtime class name tests +templates: + - deployment.yaml +tests: + - it: should not set runtimeClassName when empty + set: + webservice: + image: nginx:latest + runtimeClassName: "" + asserts: + - notExists: + path: spec.template.spec.runtimeClassName + - it: should set runtimeClassName when provided + set: + webservice: + image: nginx:latest + runtimeClassName: "gvisor" + asserts: + - equal: + path: spec.template.spec.runtimeClassName + value: "gvisor" + - it: should support kata runtime class + set: + webservice: + image: nginx:latest + runtimeClassName: "kata" + asserts: + - equal: + path: spec.template.spec.runtimeClassName + value: "kata" + - it: should work with other pod settings + set: + webservice: + image: nginx:latest + enableServiceLinks: true + runtimeClassName: "gvisor" + asserts: + - equal: + path: spec.template.spec.runtimeClassName + value: "gvisor" + - equal: + path: spec.template.spec.enableServiceLinks + value: true diff --git a/charts/wik-webservice/tests/seccompprofile_test.yaml b/charts/wik-webservice/tests/seccompprofile_test.yaml new file mode 100644 index 0000000..a59b403 --- /dev/null +++ b/charts/wik-webservice/tests/seccompprofile_test.yaml @@ -0,0 +1,53 @@ +suite: seccomp profile tests +templates: + - deployment.yaml +tests: + - it: should add seccompProfile with RuntimeDefault by default + set: + webservice: + image: nginx:latest + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.seccompProfile.type + value: "RuntimeDefault" + - it: should allow custom seccompProfile when containerSecurityContext is provided + set: + webservice: + image: nginx:latest + containerSecurityContext: + seccompProfile: + type: Localhost + localhostProfile: "profiles/custom.json" + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.seccompProfile.type + value: "Localhost" + - equal: + path: spec.template.spec.containers[0].securityContext.seccompProfile.localhostProfile + value: "profiles/custom.json" + - it: should allow disabling seccompProfile + set: + webservice: + image: nginx:latest + containerSecurityContext: + seccompProfile: + type: Unconfined + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.seccompProfile.type + value: "Unconfined" + - it: should preserve other security context settings when customizing seccompProfile + set: + webservice: + image: nginx:latest + containerSecurityContext: + seccompProfile: + type: RuntimeDefault + runAsUser: 2000 + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.seccompProfile.type + value: "RuntimeDefault" + - equal: + path: spec.template.spec.containers[0].securityContext.runAsUser + value: 2000 diff --git a/charts/wik-webservice/tests/serviceaccount_test.yaml b/charts/wik-webservice/tests/serviceaccount_test.yaml new file mode 100644 index 0000000..73d2284 --- /dev/null +++ b/charts/wik-webservice/tests/serviceaccount_test.yaml @@ -0,0 +1,73 @@ +suite: service account tests +templates: + - serviceaccount.yaml + - deployment.yaml +tests: + - it: should create a service account when create is true + set: + webservice: + image: nginx:latest + serviceAccount: + create: true + asserts: + - containsDocument: + kind: ServiceAccount + apiVersion: v1 + name: "release-name-wik-webservice" + - equal: + path: metadata.name + value: "release-name-wik-webservice" + - equal: + path: automountServiceAccountToken + value: true + - it: should not create a service account when create is false + set: + webservice: + image: nginx:latest + serviceAccount: + create: false + asserts: + - notContainsDocument: + kind: ServiceAccount + apiVersion: v1 + - equal: + path: spec.template.spec.automountServiceAccountToken + value: false + - it: should use custom service account name when provided + set: + webservice: + image: nginx:latest + serviceAccount: + create: true + name: "custom-sa" + asserts: + - containsDocument: + kind: ServiceAccount + apiVersion: v1 + name: "custom-sa" + - equal: + path: spec.template.spec.serviceAccountName + value: "custom-sa" + - it: should mount service account token when automountServiceAccountToken is true + set: + webservice: + image: nginx:latest + serviceAccount: + create: true + automountServiceAccountToken: true + asserts: + - equal: + path: automountServiceAccountToken + value: true + - it: should include annotations when provided + set: + webservice: + image: nginx:latest + serviceAccount: + create: true + annotations: + eks.amazonaws.com/role-arn: "arn:aws:iam::123456789012:role/my-role" + asserts: + - equal: + path: metadata.annotations."eks.amazonaws.com/role-arn" + value: "arn:aws:iam::123456789012:role/my-role" diff --git a/charts/wik-webservice/tests/servicemonitor_test.yaml b/charts/wik-webservice/tests/servicemonitor_test.yaml new file mode 100644 index 0000000..c3c7e61 --- /dev/null +++ b/charts/wik-webservice/tests/servicemonitor_test.yaml @@ -0,0 +1,81 @@ +suite: service monitor tests +templates: + - servicemonitor.yaml +tests: + - it: should create a ServiceMonitor when enabled and metrics enabled + set: + webservice: + image: nginx:latest + metrics: + enabled: true + path: /metrics + serviceMonitor: + enabled: true + asserts: + - containsDocument: + kind: ServiceMonitor + apiVersion: monitoring.coreos.com/v1 + name: "release-name-wik-webservice" + - equal: + path: spec.endpoints[0].port + value: "metrics" + - equal: + path: spec.endpoints[0].path + value: "/metrics" + - equal: + path: spec.endpoints[0].interval + value: "30s" + - it: should not create a ServiceMonitor when metrics disabled + set: + webservice: + image: nginx:latest + metrics: + enabled: false + serviceMonitor: + enabled: true + asserts: + - notContainsDocument: + kind: ServiceMonitor + apiVersion: monitoring.coreos.com/v1 + - it: should not create a ServiceMonitor when serviceMonitor disabled + set: + webservice: + image: nginx:latest + metrics: + enabled: true + serviceMonitor: + enabled: false + asserts: + - notContainsDocument: + kind: ServiceMonitor + apiVersion: monitoring.coreos.com/v1 + - it: should use custom configuration when provided + set: + webservice: + image: nginx:latest + metrics: + enabled: true + path: /custom-metrics + serviceMonitor: + enabled: true + interval: 60s + scrapeTimeout: 30s + honorLabels: true + additionalLabels: + release: prometheus + asserts: + - equal: + path: spec.endpoints[0].path + value: "/custom-metrics" + - equal: + path: spec.endpoints[0].interval + value: "60s" + - equal: + path: spec.endpoints[0].scrapeTimeout + value: "30s" + - equal: + path: spec.endpoints[0].honorLabels + value: true + - equal: + path: metadata.labels.release + value: "prometheus" diff --git a/charts/wik-webservice/tests/startupprobe_test.yaml b/charts/wik-webservice/tests/startupprobe_test.yaml new file mode 100644 index 0000000..5836f4e --- /dev/null +++ b/charts/wik-webservice/tests/startupprobe_test.yaml @@ -0,0 +1,74 @@ +suite: startup probe tests +templates: + - deployment.yaml +tests: + - it: should not add startupProbe when empty + set: + webservice: + image: nginx:latest + startupProbe: {} + asserts: + - notExists: + path: spec.template.spec.containers[0].startupProbe + - it: should add startupProbe when specified + set: + webservice: + image: nginx:latest + startupProbe: + httpGet: + path: /startup + port: 80 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 30 + successThreshold: 1 + asserts: + - exists: + path: spec.template.spec.containers[0].startupProbe + - equal: + path: spec.template.spec.containers[0].startupProbe.httpGet.path + value: "/startup" + - equal: + path: spec.template.spec.containers[0].startupProbe.httpGet.port + value: 80 + - equal: + path: spec.template.spec.containers[0].startupProbe.initialDelaySeconds + value: 10 + - equal: + path: spec.template.spec.containers[0].startupProbe.failureThreshold + value: 30 + - it: should support TCP socket startup probe + set: + webservice: + image: nginx:latest + startupProbe: + tcpSocket: + port: 8080 + periodSeconds: 5 + failureThreshold: 12 + asserts: + - equal: + path: spec.template.spec.containers[0].startupProbe.tcpSocket.port + value: 8080 + - equal: + path: spec.template.spec.containers[0].startupProbe.periodSeconds + value: 5 + - it: should support exec startup probe + set: + webservice: + image: nginx:latest + startupProbe: + exec: + command: + - cat + - /tmp/ready + initialDelaySeconds: 5 + periodSeconds: 10 + asserts: + - equal: + path: spec.template.spec.containers[0].startupProbe.exec.command[0] + value: "cat" + - equal: + path: spec.template.spec.containers[0].startupProbe.exec.command[1] + value: "/tmp/ready" diff --git a/charts/wik-webservice/tests/topologyspreadconstraints_test.yaml b/charts/wik-webservice/tests/topologyspreadconstraints_test.yaml new file mode 100644 index 0000000..c4d27d3 --- /dev/null +++ b/charts/wik-webservice/tests/topologyspreadconstraints_test.yaml @@ -0,0 +1,54 @@ +suite: topology spread constraints tests +templates: + - deployment.yaml +tests: + - it: should not add topologySpreadConstraints when empty + set: + webservice: + image: nginx:latest + topologySpreadConstraints: [] + asserts: + - notExists: + path: spec.topologySpreadConstraints + - it: should add topologySpreadConstraints when specified + set: + webservice: + image: nginx:latest + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + app.kubernetes.io/name: wik-webservice + app.kubernetes.io/instance: release-name + asserts: + - exists: + path: spec.topologySpreadConstraints + - equal: + path: spec.topologySpreadConstraints[0].maxSkew + value: 1 + - equal: + path: spec.topologySpreadConstraints[0].topologyKey + value: "kubernetes.io/hostname" + - equal: + path: spec.topologySpreadConstraints[0].whenUnsatisfiable + value: "DoNotSchedule" + - it: should support multiple topologySpreadConstraints + set: + webservice: + image: nginx:latest + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + - maxSkew: 1 + topologyKey: topology.kubernetes.io/zone + whenUnsatisfiable: ScheduleAnyway + asserts: + - equal: + path: spec.topologySpreadConstraints[0].topologyKey + value: "kubernetes.io/hostname" + - equal: + path: spec.topologySpreadConstraints[1].topologyKey + value: "topology.kubernetes.io/zone" diff --git a/charts/wik-webservice/values.schema.json b/charts/wik-webservice/values.schema.json index 8d4e1e6..d23845c 100644 --- a/charts/wik-webservice/values.schema.json +++ b/charts/wik-webservice/values.schema.json @@ -196,10 +196,6 @@ "type": "object", "default": {} }, - "storage": { - "type": "object", - "default": {} - }, "volumes": { "type": "array", "items": { diff --git a/charts/wik-webservice/values.yaml b/charts/wik-webservice/values.yaml index e431905..02172e4 100644 --- a/charts/wik-webservice/values.yaml +++ b/charts/wik-webservice/values.yaml @@ -3,6 +3,88 @@ general: # instead of Secret with plaintext value sealedSecrets: false +# ServiceAccount configuration +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: "" + # AutomountServiceAccountToken controls whether the service account token is automatically mounted + automountServiceAccountToken: true + +# PodDisruptionBudget configuration +podDisruptionBudget: + # Enable PodDisruptionBudget + enabled: false + # Annotations to add to the PodDisruptionBudget + annotations: {} + # Minimum available pods (mutually exclusive with maxUnavailable) + minAvailable: 1 + # Maximum unavailable pods (mutually exclusive with minAvailable) + # maxUnavailable: 1 + +# NetworkPolicy configuration +networkPolicy: + # Enable NetworkPolicy + enabled: false + # Annotations to add to the NetworkPolicy + annotations: {} + # Ingress rules (if not specified, allows traffic from ingress-nginx namespace) + ingress: [] + # Egress rules (if not specified, allows all egress) + egress: [] + +# ServiceMonitor configuration for Prometheus +serviceMonitor: + # Enable ServiceMonitor + enabled: false + # Additional labels for ServiceMonitor + additionalLabels: {} + # Annotations for ServiceMonitor + annotations: {} + # Scrape interval + interval: 30s + # Scrape timeout + scrapeTimeout: 10s + # Honor labels + honorLabels: false + # Metric relabelings + metricRelabelings: [] + # Relabelings + relabelings: [] + +# Runtime class for container isolation (gVisor, Kata, etc.) +runtimeClassName: "" + +# Pod Security Standards (Kubernetes 1.25+) +podSecurityStandard: + # Enable Pod Security Standards labels + enabled: true + # Security level: privileged, baseline, restricted + level: restricted + +# HorizontalPodAutoscaler configuration +horizontalPodAutoscaler: + # Enable HPA + enabled: false + # Minimum number of replicas + minReplicas: 1 + # Maximum number of replicas + maxReplicas: 5 + # Target CPU utilization percentage + targetCPUUtilizationPercentage: 80 + # Target memory utilization percentage + targetMemoryUtilizationPercentage: null + # Annotations for HPA + annotations: {} + # Custom metrics (advanced) + customMetrics: [] + # HPA behavior configuration + behavior: {} + webservice: # Container image (required) image: "nginx:latest" @@ -40,6 +122,25 @@ webservice: replicas: 1 port: 80 + # TopologySpreadConstraints for better pod distribution + topologySpreadConstraints: [] + # Example: Spread pods across nodes + # - maxSkew: 1 + # topologyKey: kubernetes.io/hostname + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # app.kubernetes.io/name: wik-webservice + # app.kubernetes.io/instance: release-name + # Example: Spread pods across zones + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # app.kubernetes.io/name: wik-webservice + # app.kubernetes.io/instance: release-name + service: enabled: true port: 80 @@ -99,18 +200,30 @@ webservice: # runAsGroup: 1000 # fsGroup: 1000 + # Host protection (explicitly set to secure defaults) + hostNetwork: false + hostPID: false + hostIPC: false + + # Enable service links (injects all services as environment variables) + enableServiceLinks: false + # Container-level security context containerSecurityContext: {} # allowPrivilegeEscalation: false # readOnlyRootFilesystem: true + # seccompProfile: + # type: RuntimeDefault resources: {} # requests: # memory: "512Mi" # cpu: "250m" + # ephemeral-storage: "1Gi" # limits: # memory: "1Gi" # cpu: "500m" + # ephemeral-storage: "2Gi" hostAliases: [] # - ip: "127.0.0.1" @@ -150,6 +263,16 @@ webservice: # initialDelaySeconds: 5 # periodSeconds: 5 + startupProbe: {} + # httpGet: + # path: /startup + # port: 80 + # initialDelaySeconds: 10 + # periodSeconds: 10 + # timeoutSeconds: 5 + # failureThreshold: 30 + # successThreshold: 1 + # Environment variables env: plaintext: {} @@ -171,19 +294,23 @@ webservice: # values: # - eu-west-1a - # Persistent storage (creates PVC) - storage: {} - # Example: creates a PVC named -data - # data: - # size: 10Gi - # storageClass: standard - - # Volume mounts (supports PVC, ConfigMap, Secret) + # Volume mounts (supports PVC, ConfigMap, Secret, emptyDir) volumes: [] - # Mount from PVC (requires matching entry in storage) + # Mount from PVC (storage contains the PVC spec) # - name: data # mountPath: /app/data - # storage: true + # storage: + # accessModes: + # - ReadWriteOnce + # resources: + # requests: + # storage: 10Gi + # storageClassName: standard + # + # Mount emptyDir (ephemeral storage) + # - name: cache + # mountPath: /tmp/cache + # emptyDir: {} # # Mount from ConfigMap # - name: config diff --git a/ct.yaml b/ct.yaml index 3dc9f1b..17e651f 100644 --- a/ct.yaml +++ b/ct.yaml @@ -6,6 +6,6 @@ chart-repos: - bitnami=https://charts.bitnami.com/bitnami helm-extra-args: --timeout 600s validate-maintainers: false -check-version-increment: true +check-version-increment: false validate-chart-schema: true helm-extra-set-args: --set=image.tag=latest