keepomize


Namekeepomize JSON
Version 0.1.2 PyPI version JSON
download
home_pageNone
SummaryA filter for Kubernetes manifests that resolves Keeper URIs in Secret resources using ksm
upload_time2025-08-14 05:30:44
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseNone
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"
}
        
Elapsed time: 0.40905s