From ce8aee1339519553e9e3b916fea100c70d27d0b2 Mon Sep 17 00:00:00 2001 From: Gridness Date: Mon, 15 Sep 2025 14:35:40 +0300 Subject: [PATCH] Updated repo structure and kubeseal-secrets hook - Moved existing hooks to separate subfolders under ./hooks - Updated hooks entries for kubeseal-secrets to include new args - Initialized separate documentation for kubeseal-secrets hook - Updated repo documentation to make it more generalized --- .pre-commit-hooks.yaml | 12 +++--- README.md | 11 +++-- hooks/kubeseal-secrets/README.md | 19 +++++++++ hooks/kubeseal-secrets/kubeseal-secrets.py | 49 ++++++++++++++++++++++ kubeseal-secrets.py | 24 ----------- 5 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 hooks/kubeseal-secrets/README.md create mode 100644 hooks/kubeseal-secrets/kubeseal-secrets.py delete mode 100644 kubeseal-secrets.py diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 9317f6f..65df44d 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -1,10 +1,12 @@ - id: kubeseal-secrets name: Kubeseal secrets files - entry: python3 ./kubeseal-secrets.py - language: python - args: - - "*secret*" description: | Finds secret files matching the pattern and creates sealed secrets using kubeseal. + entry: python3 ./hooks/kubeseal-secrets/kubeseal-secrets.py + language: python + args: + - --controller-name=sealed-secrets + - --controller-namespace=sealed-secrets + pass_filenames: true + files: "*secret*.(yaml|yml)$" stages: [commit] - pass_filenames: false diff --git a/README.md b/README.md index e8a6f50..949ff69 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ Integrate the Kubeseal Hook in Your Project ```yaml repos: - repo: https://github.com/Gridness/k8s-hooks - rev: 2.0 # or a specific tag/commit + rev: 2.0 # or a specific tag/commit hooks: - - id: kubeseal-secrets # or any other script you wanna run - args: # Specify args for the hook - - '*secret*' + - id: hook-id # id of the hook + args: [""] # list of args of the chosen hook + files: [""] # list of files the hook gonna run over (if supported) ``` 2. Install pre-commit hooks: ```bash @@ -27,11 +27,10 @@ pre-commit install 3. On each commit, the hook do it's job # Requirements -- [kubeseal](https://github.com/bitnami-labs/sealed-secrets) CLI must be installed and available in your PATH - [pre-commit](https://pre-commit.com/) framework installed in your local environment # Contributing Contributions to add new hooks, improve existing ones, or fix issues are welcome! Please open issues or pull requests. # License -This repository is licensed under the MIT License +This repository is licensed under the MIT License. See LICENSE file for details diff --git a/hooks/kubeseal-secrets/README.md b/hooks/kubeseal-secrets/README.md new file mode 100644 index 0000000..2e57854 --- /dev/null +++ b/hooks/kubeseal-secrets/README.md @@ -0,0 +1,19 @@ +# Kubeseal Secrets Hook +This pre-commit hook scans your Git repository for secret files matching a configurable pattern and creates sealed secrets using `kubeseal`. It ensures that all secrets are encrypted before being committed, enhancing security and compliance. + +You can specify regex pattern by which the script will look for secrets files in your repo directory in the hook `args` section of your pre-commit config +# Usage +```yaml +repos: + - repo: https://github.com/Gridness/k8s-hooks + rev: 3.0 # or a specific tag/commit + hooks: + - id: kubeseal-secrets + args: # you can ommit these values if you want to use the default ones listed below + - "--controller-name sealed-secrets" + - "--controller-namespace sealed-secrets" + files: ["*secret*.yaml"] # regex pattern of your secrets manifests filenames +``` +# Requirements +- [sealed-secrets](https://artifacthub.io/packages/helm/bitnami-labs/sealed-secrets) controller must be deployed in your Kubernetes cluster +- [kubeseal](https://github.com/bitnami-labs/sealed-secrets) CLI must be installed on the machine you are working with secrets and running this hook diff --git a/hooks/kubeseal-secrets/kubeseal-secrets.py b/hooks/kubeseal-secrets/kubeseal-secrets.py new file mode 100644 index 0000000..3337db3 --- /dev/null +++ b/hooks/kubeseal-secrets/kubeseal-secrets.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +import argparse +import subprocess +import sys +from pathlib import Path + +def seal_secrets(files, controller_name, controller_namespace): + for file_path in files: + file = Path(file_path) + if not file.exists(): + print(f"Warning: File {file} does not exist, skipping") + continue + + sealed_file = file.with_suffix(file.suffix + ".sealed.yaml") + if sealed_file.exists(): + print(f"Sealed file already exists: {sealed_file}, skipping") + continue + + kubeseal_cmd = [ + "kubeseal", + "--format", "yaml", + "--controller-name", controller_name, + "--controller-namespace", controller_namespace, + ] + + try: + with Path(file).open("rb") as f: + result = subprocess.run( + kubeseal_cmd, + input=f.read(), + capture_output=True, + check=True, + text=False, + ) + sealed_file.write_bytes(result.stdout) + print(f"✅ Sealed secret created: {sealed_file}") + except subprocess.CalledProcessError as e: + print(f"❌ Error sealing {file}: {e.stderr.decode()}") + sys.exit(1) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Seal Kubernetes secrets using kubeseal") + parser.add_argument("--controller-name", required=True, help="Name of the sealed secrets controller") + parser.add_argument("--controller-namespace", required=True, help="Namespace of the sealed secrets controller") + parser.add_argument("files", nargs="+", help="Secret files to process") + + args = parser.parse_args() + seal_secrets(args.files, args.controller_name, args.controller_namespace) diff --git a/kubeseal-secrets.py b/kubeseal-secrets.py deleted file mode 100644 index 584cfd1..0000000 --- a/kubeseal-secrets.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 - -import subprocess -import sys -from pathlib import Path - -def seal_secrets(pattern="*secret*"): - secrets = list(Path(".").rglob(pattern)) - for file in secrets: - sealed_file = file.with_suffix(file.suffix + ".sealed.yaml") - if not sealed_file.exists(): - with open(file, "rb") as f: - result = subprocess.run( - ["kubeseal", "--format", "yaml"], - input=f.read(), - capture_output=True, - check=True - ) - sealed_file.write_bytes(result.stdout) - print(f"Sealed secret created: {sealed_file}") - -if __name__ == "__main__": - pattern = sys.argv[1] if len(sys.argv) > 1 else "*secret*" - seal_secrets(pattern)