Name | keepomize JSON |
Version |
0.1.2
JSON |
| download |
home_page | None |
Summary | A filter for Kubernetes manifests that resolves Keeper URIs in Secret resources using ksm |
upload_time | 2025-08-14 05:30:44 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.8 |
license | None |
keywords |
kubernetes
secrets
keeper
kustomize
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Keepomize
A filter for Kubernetes manifests that resolves Keeper URIs in Secret resources using the `ksm` command-line tool.
## Overview
Keepomize is designed to work in a pipeline after Kustomize to resolve Keeper URIs in Kubernetes Secret manifests. It reads a multi-document YAML stream from stdin, finds any Kubernetes Secret resources, and replaces Keeper URIs (`keeper://RECORDID/fieldspec`) in their `stringData` and `data` fields by resolving them through `ksm`.
## Prerequisites
- Python 3.8 or higher
- The `ksm` command-line tool must be installed and available in your PATH
- Access to Keeper secrets that you want to resolve
- Any `KSM_*` environment variables needed for `ksm` configuration (automatically passed through)
## Installation
### From PyPI
```bash
pip install keepomize
```
### From source
```bash
git clone https://github.com/nathanic/keepomize.git
cd keepomize
uv sync
uv run keepomize --help
```
### Development installation
```bash
git clone https://github.com/nathanic/keepomize.git
cd keepomize
uv sync --dev
```
## Usage
### Basic usage
```bash
# Use with kustomize and kubectl
kustomize build overlays/production | keepomize | kubectl apply -f -
# Use with kustomize and oc (OpenShift)
kustomize build overlays/production | keepomize | oc apply -f -
```
### Example Secret manifest
Before processing:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: my-app-secrets
namespace: default
type: Opaque
stringData:
database-password: keeper://MySQL Database/field/password
api-key: keeper://API Keys/field/api_key
username: keeper://MySQL Database/field/login
data:
secret-token: keeper://Auth Service/field/token # Will be base64 encoded
```
After processing with keepomize:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: my-app-secrets
namespace: default
type: Opaque
stringData:
database-password: my-actual-password
api-key: sk-1234567890abcdef
username: mysql_user
data:
secret-token: bXktYWN0dWFsLXRva2Vu # base64 encoded value
```
### Keeper URI format
Keeper URIs use [Keeper notation](https://docs.keeper.io/en/keeperpam/secrets-manager/about/keeper-notation) which follows this format:
```
keeper://<TITLE|UID>/<selector>/<parameters>[[predicate1][predicate2]]
```
Common examples for Kubernetes Secrets:
```
keeper://MySQL Creds/field/password
keeper://API Keys/field/api_key
keeper://Contact/field/name[first]
keeper://Record/custom_field/phone[1][number]
```
Where:
- **First segment**: Record title or unique identifier (UID)
- **Selector**: `field` for standard fields, `custom_field` for custom fields, `file` for files
- **Parameters**: Field name or other identifiers
- **Predicates** (optional): Array indices `[0]` and sub-field access `[property]`
**Note**: Special characters (`/`, `\`, `[`, `]`) in record details must be escaped with backslash.
### How it works
1. **Input**: Reads multi-document YAML from stdin
2. **Processing**:
- Identifies Kubernetes Secret resources (where `kind: Secret`)
- Scans `stringData` and `data` fields for Keeper URIs
- Resolves URIs using `ksm secret notation` command
- For `data` fields, base64 encodes the resolved values
3. **Output**: Writes the modified YAML to stdout
### Integration with CI/CD
```yaml
# GitHub Actions example
- name: Deploy with secret resolution
run: |
kustomize build overlays/production | keepomize | kubectl apply -f -
env:
KSM_CONFIG: ${{ secrets.KSM_CONFIG }}
KSM_TOKEN: ${{ secrets.KSM_TOKEN }}
# Any KSM_* environment variables are automatically passed to ksm
```
## Error handling
Keepomize will:
- Exit with status code 1 if `ksm` is not found in PATH
- Exit with status code 1 if any Keeper URI fails to resolve
- Print error messages to stderr while preserving stdout for the YAML output
- Preserve all non-Secret resources unchanged
## Development
### Running tests
```bash
uv run pytest
```
### Building for distribution
```bash
uv build
```
### Publishing to PyPI
```bash
uv publish
```
## License
MIT License - see LICENSE file for details.
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Ensure all tests pass
6. Submit a pull request
## Changelog
### 0.1.2
- **Critical Bug Fixes**:
- Fixed trailing newline handling - ksm output now has trailing newlines stripped to prevent malformed secret values
- Fixed environment variable inheritance - ksm subprocess now inherits full environment (preserves HOME, SSL_CERT_FILE, proxy settings, etc.)
- **Testing**: Added comprehensive tests for newline handling edge cases and environment inheritance
### 0.1.1
- **Bug Fix**: Fixed CLI argument parsing to restore --help functionality
- **Testing**: Added sys.argv patches to CLI tests for proper argument handling
### 0.1.0
- Initial release
- Support for resolving Keeper URIs in Secret stringData and data fields
- CLI tool with proper error handling
- Full test suite
Raw data
{
"_id": null,
"home_page": null,
"name": "keepomize",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "Nathan Stien <nathanism@gmail.com>",
"keywords": "kubernetes, secrets, keeper, kustomize",
"author": null,
"author_email": "Nathan Stien <nathanism@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/e7/7a/298985d8d54106102b977bd30cb5dd7cb0bd9db52a85a519aba940231515/keepomize-0.1.2.tar.gz",
"platform": null,
"description": "# Keepomize\n\nA filter for Kubernetes manifests that resolves Keeper URIs in Secret resources using the `ksm` command-line tool.\n\n## Overview\n\nKeepomize is designed to work in a pipeline after Kustomize to resolve Keeper URIs in Kubernetes Secret manifests. It reads a multi-document YAML stream from stdin, finds any Kubernetes Secret resources, and replaces Keeper URIs (`keeper://RECORDID/fieldspec`) in their `stringData` and `data` fields by resolving them through `ksm`.\n\n## Prerequisites\n\n- Python 3.8 or higher\n- The `ksm` command-line tool must be installed and available in your PATH\n- Access to Keeper secrets that you want to resolve\n- Any `KSM_*` environment variables needed for `ksm` configuration (automatically passed through)\n\n## Installation\n\n### From PyPI\n\n```bash\npip install keepomize\n```\n\n### From source\n\n```bash\ngit clone https://github.com/nathanic/keepomize.git\ncd keepomize\nuv sync\nuv run keepomize --help\n```\n\n### Development installation\n\n```bash\ngit clone https://github.com/nathanic/keepomize.git\ncd keepomize\nuv sync --dev\n```\n\n## Usage\n\n### Basic usage\n\n```bash\n# Use with kustomize and kubectl\nkustomize build overlays/production | keepomize | kubectl apply -f -\n\n# Use with kustomize and oc (OpenShift)\nkustomize build overlays/production | keepomize | oc apply -f -\n```\n\n### Example Secret manifest\n\nBefore processing:\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: my-app-secrets\n namespace: default\ntype: Opaque\nstringData:\n database-password: keeper://MySQL Database/field/password\n api-key: keeper://API Keys/field/api_key\n username: keeper://MySQL Database/field/login\ndata:\n secret-token: keeper://Auth Service/field/token # Will be base64 encoded\n```\n\nAfter processing with keepomize:\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: my-app-secrets\n namespace: default\ntype: Opaque\nstringData:\n database-password: my-actual-password\n api-key: sk-1234567890abcdef\n username: mysql_user\ndata:\n secret-token: bXktYWN0dWFsLXRva2Vu # base64 encoded value\n```\n\n### Keeper URI format\n\nKeeper URIs use [Keeper notation](https://docs.keeper.io/en/keeperpam/secrets-manager/about/keeper-notation) which follows this format:\n```\nkeeper://<TITLE|UID>/<selector>/<parameters>[[predicate1][predicate2]]\n```\n\nCommon examples for Kubernetes Secrets:\n```\nkeeper://MySQL Creds/field/password\nkeeper://API Keys/field/api_key\nkeeper://Contact/field/name[first]\nkeeper://Record/custom_field/phone[1][number]\n```\n\nWhere:\n- **First segment**: Record title or unique identifier (UID)\n- **Selector**: `field` for standard fields, `custom_field` for custom fields, `file` for files\n- **Parameters**: Field name or other identifiers\n- **Predicates** (optional): Array indices `[0]` and sub-field access `[property]`\n\n**Note**: Special characters (`/`, `\\`, `[`, `]`) in record details must be escaped with backslash.\n\n### How it works\n\n1. **Input**: Reads multi-document YAML from stdin\n2. **Processing**: \n - Identifies Kubernetes Secret resources (where `kind: Secret`)\n - Scans `stringData` and `data` fields for Keeper URIs\n - Resolves URIs using `ksm secret notation` command\n - For `data` fields, base64 encodes the resolved values\n3. **Output**: Writes the modified YAML to stdout\n\n### Integration with CI/CD\n\n```yaml\n# GitHub Actions example\n- name: Deploy with secret resolution\n run: |\n kustomize build overlays/production | keepomize | kubectl apply -f -\n env:\n KSM_CONFIG: ${{ secrets.KSM_CONFIG }}\n KSM_TOKEN: ${{ secrets.KSM_TOKEN }}\n # Any KSM_* environment variables are automatically passed to ksm\n```\n\n## Error handling\n\nKeepomize will:\n- Exit with status code 1 if `ksm` is not found in PATH\n- Exit with status code 1 if any Keeper URI fails to resolve\n- Print error messages to stderr while preserving stdout for the YAML output\n- Preserve all non-Secret resources unchanged\n\n## Development\n\n### Running tests\n\n```bash\nuv run pytest\n```\n\n### Building for distribution\n\n```bash\nuv build\n```\n\n### Publishing to PyPI\n\n```bash\nuv publish\n```\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests for new functionality\n5. Ensure all tests pass\n6. Submit a pull request\n\n## Changelog\n\n### 0.1.2\n\n- **Critical Bug Fixes**:\n - Fixed trailing newline handling - ksm output now has trailing newlines stripped to prevent malformed secret values\n - Fixed environment variable inheritance - ksm subprocess now inherits full environment (preserves HOME, SSL_CERT_FILE, proxy settings, etc.)\n- **Testing**: Added comprehensive tests for newline handling edge cases and environment inheritance\n\n### 0.1.1\n\n- **Bug Fix**: Fixed CLI argument parsing to restore --help functionality\n- **Testing**: Added sys.argv patches to CLI tests for proper argument handling\n\n### 0.1.0\n\n- Initial release\n- Support for resolving Keeper URIs in Secret stringData and data fields\n- CLI tool with proper error handling\n- Full test suite\n",
"bugtrack_url": null,
"license": null,
"summary": "A filter for Kubernetes manifests that resolves Keeper URIs in Secret resources using ksm",
"version": "0.1.2",
"project_urls": {
"Bug Tracker": "https://github.com/nathanic/keepomize/issues",
"Documentation": "https://github.com/nathanic/keepomize#readme",
"Homepage": "https://github.com/nathanic/keepomize",
"Repository": "https://github.com/nathanic/keepomize"
},
"split_keywords": [
"kubernetes",
" secrets",
" keeper",
" kustomize"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "a1230b2739d3a8e4f52752df5624acc8d55cdd643e6a7bd50d1c0710318e67b7",
"md5": "0ee76d2cd76accc0cd416d884755b0f9",
"sha256": "30ab270c813e09a56391e563d5ac4ee1755d56dda4486706834bcbcc0362649f"
},
"downloads": -1,
"filename": "keepomize-0.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0ee76d2cd76accc0cd416d884755b0f9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 7881,
"upload_time": "2025-08-14T05:30:42",
"upload_time_iso_8601": "2025-08-14T05:30:42.364159Z",
"url": "https://files.pythonhosted.org/packages/a1/23/0b2739d3a8e4f52752df5624acc8d55cdd643e6a7bd50d1c0710318e67b7/keepomize-0.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "e77a298985d8d54106102b977bd30cb5dd7cb0bd9db52a85a519aba940231515",
"md5": "7f98a33b4ee038e7f469d1530b6c49c2",
"sha256": "794bf9e62d90ba46afa1d16d03954aacc5c29c97b4f989155692ceb6a03dbbd9"
},
"downloads": -1,
"filename": "keepomize-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "7f98a33b4ee038e7f469d1530b6c49c2",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 10176,
"upload_time": "2025-08-14T05:30:44",
"upload_time_iso_8601": "2025-08-14T05:30:44.345273Z",
"url": "https://files.pythonhosted.org/packages/e7/7a/298985d8d54106102b977bd30cb5dd7cb0bd9db52a85a519aba940231515/keepomize-0.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-14 05:30:44",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "nathanic",
"github_project": "keepomize",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "keepomize"
}