isops


Nameisops JSON
Version 0.2.0 PyPI version JSON
download
home_pagehttps://github.com/lorenzophys/isops
SummaryUtility to ensure SOPS secrets are encrypterd.
upload_time2023-01-01 20:24:22
maintainer
docs_urlNone
authorLorenzo Maffioli
requires_python>=3.7,<4.0
license
keywords isops sops secrets
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # IsOPS: **Is** **OP**erations **S**ecure

![release](https://img.shields.io/github/v/release/lorenzophys/isops)
[![codecov](https://codecov.io/gh/lorenzophys/isops/branch/main/graph/badge.svg?token=7RQ5P3X22D)](https://codecov.io/gh/lorenzophys/isops)
![GitHub Workflow Status (with branch)](https://img.shields.io/github/actions/workflow/status/lorenzophys/isops/test-workflow.yml?branch=main&label=tests)
![pver](https://img.shields.io/pypi/pyversions/isops)
![MIT](https://img.shields.io/github/license/lorenzophys/isops)

```ascii
__/\\\\\\\\\\\____________________/\\\\\_______/\\\\\\\\\\\\\_______/\\\\\\\\\\\___        
 _\/////\\\///___________________/\\\///\\\____\/\\\/////////\\\___/\\\/////////\\\_       
  _____\/\\\____________________/\\\/__\///\\\__\/\\\_______\/\\\__\//\\\______\///__      
   _____\/\\\______/\\\\\\\\\\__/\\\______\//\\\_\/\\\\\\\\\\\\\/____\////\\\_________     
    _____\/\\\_____\/\\\//////__\/\\\_______\/\\\_\/\\\/////////_________\////\\\______    
     _____\/\\\_____\/\\\\\\\\\\_\//\\\______/\\\__\/\\\_____________________\////\\\___   
      _____\/\\\_____\////////\\\__\///\\\__/\\\____\/\\\______________/\\\______\//\\\__  
       __/\\\\\\\\\\\__/\\\\\\\\\\____\///\\\\\/_____\/\\\_____________\///\\\\\\\\\\\/___ 
        _\///////////__\//////////_______\/////_______\///________________\///////////_____

```

IsOPS (**Is** **OP**erations **S**ecure) is a minimal command line utility that helps you ensure that your secrets are encrypted correctly with [sops](https://github.com/mozilla/sops) before committing them. `isops` will read your configuration files, will scan all your secrets and alerts you if it finds any key that should be encrypted but it's not.

## Installation

You can install `isops` via `pip`:

```console
user@laptop:~$ pip install isops
```

The CLI is minimal:

```console
user@laptop:~$ isops
Usage: isops [OPTIONS] PATH

  Utility to ensure all SOPS secrets are encrypterd.

Options:
  -s, --summary            Print a summary at the end of the checks.
  -h, --help               Show this message and exit.
  -v, --version            Show the version and exit.
  -r, --config-regex TEXT  The regex that matches all the config files to use.
                           [required]
```

You must provide a directory to scan and a regex that matches all the sops configuration files.

## How it works?

`isops` is called with a directory and a regex. Then:

1. It finds the config files using the provided regex.
2. For each rule in `creation_rules` it finds the files according to the `path_regex`.
3. For each file found, it scans all the keys, no matter how nested the yaml is, in search for those keys that match the `encrypted_regex`.
4. For each matched key, it checks if the associated value matches the sops regex `"^ENC\[AES256_GCM,data:(.+),iv:(.+),tag:(.+),type:(.+)\]"`.

If the config file doesn't provide a `path_regex` or a `encrypted_regex`, the default values are, respectively, `".ya?ml$"` and `""`.

## Usage example

Suppose you have this situation:

```text
example
├── .sops.yaml
└── secret.yaml
```

A `.sops.yaml`:

```yaml
creation_rules:
  - path_regex: (.*)?secret.yaml$
    encrypted_regex: "^(data|stringData)$"
    pgp: "FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4"
```

and a `secret.yaml`:

```yaml
apiVersion: v1
data:
  key: aGhkZDg4OGRoODRmaDQ4ZmJlbnNta21rbHdtc2k4
kind: Secret
metadata:
  name: api-key
type: Opaque
```

If you run `isops` you get a warning because your secret is not encrypted:

```console
user@laptop:~$ isops ./example --config-regex .sops.yaml
Found config file: example/.sops.yaml
example/secret.yaml::key [UNSAFE]
user@laptop:~$ echo $?
1
```

If the same secret is encrypted with sops:

```yaml
apiVersion: v1
data:
    key: ENC[AES256_GCM,data:iCBh27Ort/dNVhP9D4y/AqI5d78U+2EHtHPX9u0/s9ANhA2VeqKSOQ==,iv:HkQVUgB6nvN3TU355K/PTU2NroahHAdoJhzJdgZFMwo=,tag:ayNppVmYJ/MLGrW9RtjV1A==,type:str]
kind: Secret
metadata:
    name: api-key
type: Opaque
sops:
    etc...

```

then `isops` will give you the green light:

```console
user@laptop:~$ isops ./example --config-regex .sops.yaml
Found config file: example/.sops.yaml
example/secret.yaml::key [SAFE]
user@laptop:~$ echo $?
0
```

## Another example

You can have a more complicated scenario where there are multiple sops configuration files, multiple environments and lots of secrets.

Suppose you have this situation:

```text
example
├── .sops
│   ├── sops-dev.yaml
│   └── sops-prod.yaml
├── dev
│   ├── api-key-secret.yaml        <- Encrypted
│   ├── db-password-secret.yaml    <- Encrypted
│   ├── deployment.yaml
│   └── service.yaml
└── prod
    ├── api-key-secret.yaml        <- Not encrypted!
    ├── db-password-secret.yaml    <- Encrypted
    ├── deployment.yaml
    └── service.yaml
```

Then if you run `isops` you get:

```console
user@laptop:~$ isops example --config-regex "example/.sops/(.*).yaml$"
Found config file: example/.sops/sops-dev.yaml
Found config file: example/.sops/sops-prod.yaml
example/dev/db-password-secret.yaml::password [SAFE]
example/dev/api-key-secret.yaml::key [SAFE]
example/prod/db-password-secret.yaml::password [SAFE]
example/prod/api-key-secret.yaml::key [UNSAFE]
```

Sometimes the list of secret is very long: you can enable a small summary at the end with the `--summary` option:

```console
user@laptop:~$ isops example --config-regex "example/.sops/(.*).yaml$" --summary
Found config file: example/.sops/sops-dev.yaml
Found config file: example/.sops/sops-prod.yaml
example/dev/db-password-secret.yaml::password [SAFE]
example/dev/api-key-secret.yaml::key [SAFE]
example/prod/db-password-secret.yaml::password [SAFE]
example/prod/api-key-secret.yaml::key [UNSAFE]
---
Summary:
UNSAFE secret 'key' in 'example/prod/api-key-secret.yaml'
3 safe 1 unsafe
```

The previous example can be found in the `example` directory. The sample application was generated by [ChatGPT](https://chat.openai.com/chat) with the prompt: "Please, generate an example Kubernetes application with two secrets".

## Pre-commit hook

`isops` can be also used as a [pre-commit](https://pre-commit.com) hook. For example:

```yaml
repos:
  - repo: https://github.com/lorenzophys/isops
    rev: v0.2.0
    hooks:
      - id: isops
        args:
          - --config-regex=.sops/(.*).ya?ml$
          - --summary
```

## License

This project is licensed under the **MIT License** - see the *LICENSE* file for details.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/lorenzophys/isops",
    "name": "isops",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7,<4.0",
    "maintainer_email": "",
    "keywords": "isops,sops,secrets",
    "author": "Lorenzo Maffioli",
    "author_email": "lorenzo.maffioli@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/d0/7a/4db8adaa3a42cc3fadf663846a67d44c315fec87ed0c113102c770cca5d2/isops-0.2.0.tar.gz",
    "platform": null,
    "description": "# IsOPS: **Is** **OP**erations **S**ecure\n\n![release](https://img.shields.io/github/v/release/lorenzophys/isops)\n[![codecov](https://codecov.io/gh/lorenzophys/isops/branch/main/graph/badge.svg?token=7RQ5P3X22D)](https://codecov.io/gh/lorenzophys/isops)\n![GitHub Workflow Status (with branch)](https://img.shields.io/github/actions/workflow/status/lorenzophys/isops/test-workflow.yml?branch=main&label=tests)\n![pver](https://img.shields.io/pypi/pyversions/isops)\n![MIT](https://img.shields.io/github/license/lorenzophys/isops)\n\n```ascii\n__/\\\\\\\\\\\\\\\\\\\\\\____________________/\\\\\\\\\\_______/\\\\\\\\\\\\\\\\\\\\\\\\\\_______/\\\\\\\\\\\\\\\\\\\\\\___        \n _\\/////\\\\\\///___________________/\\\\\\///\\\\\\____\\/\\\\\\/////////\\\\\\___/\\\\\\/////////\\\\\\_       \n  _____\\/\\\\\\____________________/\\\\\\/__\\///\\\\\\__\\/\\\\\\_______\\/\\\\\\__\\//\\\\\\______\\///__      \n   _____\\/\\\\\\______/\\\\\\\\\\\\\\\\\\\\__/\\\\\\______\\//\\\\\\_\\/\\\\\\\\\\\\\\\\\\\\\\\\\\/____\\////\\\\\\_________     \n    _____\\/\\\\\\_____\\/\\\\\\//////__\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\/////////_________\\////\\\\\\______    \n     _____\\/\\\\\\_____\\/\\\\\\\\\\\\\\\\\\\\_\\//\\\\\\______/\\\\\\__\\/\\\\\\_____________________\\////\\\\\\___   \n      _____\\/\\\\\\_____\\////////\\\\\\__\\///\\\\\\__/\\\\\\____\\/\\\\\\______________/\\\\\\______\\//\\\\\\__  \n       __/\\\\\\\\\\\\\\\\\\\\\\__/\\\\\\\\\\\\\\\\\\\\____\\///\\\\\\\\\\/_____\\/\\\\\\_____________\\///\\\\\\\\\\\\\\\\\\\\\\/___ \n        _\\///////////__\\//////////_______\\/////_______\\///________________\\///////////_____\n\n```\n\nIsOPS (**Is** **OP**erations **S**ecure) is a minimal command line utility that helps you ensure that your secrets are encrypted correctly with [sops](https://github.com/mozilla/sops) before committing them. `isops` will read your configuration files, will scan all your secrets and alerts you if it finds any key that should be encrypted but it's not.\n\n## Installation\n\nYou can install `isops` via `pip`:\n\n```console\nuser@laptop:~$ pip install isops\n```\n\nThe CLI is minimal:\n\n```console\nuser@laptop:~$ isops\nUsage: isops [OPTIONS] PATH\n\n  Utility to ensure all SOPS secrets are encrypterd.\n\nOptions:\n  -s, --summary            Print a summary at the end of the checks.\n  -h, --help               Show this message and exit.\n  -v, --version            Show the version and exit.\n  -r, --config-regex TEXT  The regex that matches all the config files to use.\n                           [required]\n```\n\nYou must provide a directory to scan and a regex that matches all the sops configuration files.\n\n## How it works?\n\n`isops` is called with a directory and a regex. Then:\n\n1. It finds the config files using the provided regex.\n2. For each rule in `creation_rules` it finds the files according to the `path_regex`.\n3. For each file found, it scans all the keys, no matter how nested the yaml is, in search for those keys that match the `encrypted_regex`.\n4. For each matched key, it checks if the associated value matches the sops regex `\"^ENC\\[AES256_GCM,data:(.+),iv:(.+),tag:(.+),type:(.+)\\]\"`.\n\nIf the config file doesn't provide a `path_regex` or a `encrypted_regex`, the default values are, respectively, `\".ya?ml$\"` and `\"\"`.\n\n## Usage example\n\nSuppose you have this situation:\n\n```text\nexample\n\u251c\u2500\u2500 .sops.yaml\n\u2514\u2500\u2500 secret.yaml\n```\n\nA `.sops.yaml`:\n\n```yaml\ncreation_rules:\n  - path_regex: (.*)?secret.yaml$\n    encrypted_regex: \"^(data|stringData)$\"\n    pgp: \"FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4\"\n```\n\nand a `secret.yaml`:\n\n```yaml\napiVersion: v1\ndata:\n  key: aGhkZDg4OGRoODRmaDQ4ZmJlbnNta21rbHdtc2k4\nkind: Secret\nmetadata:\n  name: api-key\ntype: Opaque\n```\n\nIf you run `isops` you get a warning because your secret is not encrypted:\n\n```console\nuser@laptop:~$ isops ./example --config-regex .sops.yaml\nFound config file: example/.sops.yaml\nexample/secret.yaml::key [UNSAFE]\nuser@laptop:~$ echo $?\n1\n```\n\nIf the same secret is encrypted with sops:\n\n```yaml\napiVersion: v1\ndata:\n    key: ENC[AES256_GCM,data:iCBh27Ort/dNVhP9D4y/AqI5d78U+2EHtHPX9u0/s9ANhA2VeqKSOQ==,iv:HkQVUgB6nvN3TU355K/PTU2NroahHAdoJhzJdgZFMwo=,tag:ayNppVmYJ/MLGrW9RtjV1A==,type:str]\nkind: Secret\nmetadata:\n    name: api-key\ntype: Opaque\nsops:\n    etc...\n\n```\n\nthen `isops` will give you the green light:\n\n```console\nuser@laptop:~$ isops ./example --config-regex .sops.yaml\nFound config file: example/.sops.yaml\nexample/secret.yaml::key [SAFE]\nuser@laptop:~$ echo $?\n0\n```\n\n## Another example\n\nYou can have a more complicated scenario where there are multiple sops configuration files, multiple environments and lots of secrets.\n\nSuppose you have this situation:\n\n```text\nexample\n\u251c\u2500\u2500 .sops\n\u2502   \u251c\u2500\u2500 sops-dev.yaml\n\u2502   \u2514\u2500\u2500 sops-prod.yaml\n\u251c\u2500\u2500 dev\n\u2502   \u251c\u2500\u2500 api-key-secret.yaml        <- Encrypted\n\u2502   \u251c\u2500\u2500 db-password-secret.yaml    <- Encrypted\n\u2502   \u251c\u2500\u2500 deployment.yaml\n\u2502   \u2514\u2500\u2500 service.yaml\n\u2514\u2500\u2500 prod\n    \u251c\u2500\u2500 api-key-secret.yaml        <- Not encrypted!\n    \u251c\u2500\u2500 db-password-secret.yaml    <- Encrypted\n    \u251c\u2500\u2500 deployment.yaml\n    \u2514\u2500\u2500 service.yaml\n```\n\nThen if you run `isops` you get:\n\n```console\nuser@laptop:~$ isops example --config-regex \"example/.sops/(.*).yaml$\"\nFound config file: example/.sops/sops-dev.yaml\nFound config file: example/.sops/sops-prod.yaml\nexample/dev/db-password-secret.yaml::password [SAFE]\nexample/dev/api-key-secret.yaml::key [SAFE]\nexample/prod/db-password-secret.yaml::password [SAFE]\nexample/prod/api-key-secret.yaml::key [UNSAFE]\n```\n\nSometimes the list of secret is very long: you can enable a small summary at the end with the `--summary` option:\n\n```console\nuser@laptop:~$ isops example --config-regex \"example/.sops/(.*).yaml$\" --summary\nFound config file: example/.sops/sops-dev.yaml\nFound config file: example/.sops/sops-prod.yaml\nexample/dev/db-password-secret.yaml::password [SAFE]\nexample/dev/api-key-secret.yaml::key [SAFE]\nexample/prod/db-password-secret.yaml::password [SAFE]\nexample/prod/api-key-secret.yaml::key [UNSAFE]\n---\nSummary:\nUNSAFE secret 'key' in 'example/prod/api-key-secret.yaml'\n3 safe 1 unsafe\n```\n\nThe previous example can be found in the `example` directory. The sample application was generated by [ChatGPT](https://chat.openai.com/chat) with the prompt: \"Please, generate an example Kubernetes application with two secrets\".\n\n## Pre-commit hook\n\n`isops` can be also used as a [pre-commit](https://pre-commit.com) hook. For example:\n\n```yaml\nrepos:\n  - repo: https://github.com/lorenzophys/isops\n    rev: v0.2.0\n    hooks:\n      - id: isops\n        args:\n          - --config-regex=.sops/(.*).ya?ml$\n          - --summary\n```\n\n## License\n\nThis project is licensed under the **MIT License** - see the *LICENSE* file for details.\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Utility to ensure SOPS secrets are encrypterd.",
    "version": "0.2.0",
    "split_keywords": [
        "isops",
        "sops",
        "secrets"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "2b284e57a0eb8f0c3a3c00bb9ba87890",
                "sha256": "1b7caa14732887f065d67ef971de21f2f130501b402c2b30a1b7cc231cf04d98"
            },
            "downloads": -1,
            "filename": "isops-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "2b284e57a0eb8f0c3a3c00bb9ba87890",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7,<4.0",
            "size": 8153,
            "upload_time": "2023-01-01T20:24:20",
            "upload_time_iso_8601": "2023-01-01T20:24:20.873033Z",
            "url": "https://files.pythonhosted.org/packages/6a/22/3a6a5c1651bff6b074796fe949903f1ad865b3ce1dd2e03b0256b12987f2/isops-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "f13c875688f88bf34f6ad24e82eaa57a",
                "sha256": "51b70087f41b6aefa72f3dfb593fd08c4ecaa4dacd2af0b28fa861ce70d15f1f"
            },
            "downloads": -1,
            "filename": "isops-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "f13c875688f88bf34f6ad24e82eaa57a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7,<4.0",
            "size": 8411,
            "upload_time": "2023-01-01T20:24:22",
            "upload_time_iso_8601": "2023-01-01T20:24:22.079744Z",
            "url": "https://files.pythonhosted.org/packages/d0/7a/4db8adaa3a42cc3fadf663846a67d44c315fec87ed0c113102c770cca5d2/isops-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-01-01 20:24:22",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "lorenzophys",
    "github_project": "isops",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "isops"
}
        
Elapsed time: 0.02257s