From bf404828a724bf71a9188d33d810ab9e031b63fd Mon Sep 17 00:00:00 2001 From: Carlos Date: Tue, 4 Jul 2023 17:05:39 +0200 Subject: [PATCH] Add profile_name to all actions, add revoke_token action, bump hvac to 1.1.0 --- .github/workflows/build_and_test.yaml | 8 +- CHANGES.md | 3 + README.jinja | 7 +- README.md | 120 ++++++++++++++++---------- actions/create_token.py | 42 ++++++--- actions/create_token.yaml | 56 +++++++++--- actions/delete.py | 6 +- actions/delete.yaml | 14 +-- actions/delete_policy.py | 3 +- actions/delete_policy.yaml | 14 +-- actions/generate_secret.yaml | 9 +- actions/get_policy.py | 3 +- actions/get_policy.yaml | 14 +-- actions/is_initialized.py | 5 +- actions/is_initialized.yaml | 5 ++ actions/lib/action.py | 10 +-- actions/list_policies.py | 5 +- actions/list_policies.yaml | 5 ++ actions/read.py | 9 +- actions/read.yaml | 14 +-- actions/read_kv.py | 16 ++-- actions/read_kv.yaml | 45 ++++++---- actions/revoke_token.py | 17 ++++ actions/revoke_token.yaml | 21 +++++ actions/set_policy.py | 3 +- actions/set_policy.yaml | 24 +++--- actions/write.py | 3 +- actions/write.yaml | 24 +++--- actions/write_secret.py | 31 ++++--- actions/write_secret.yaml | 9 +- requirements-tests.txt | 1 - requirements.txt | 2 +- 32 files changed, 360 insertions(+), 188 deletions(-) create mode 100644 actions/revoke_token.py create mode 100644 actions/revoke_token.yaml diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml index 82ee126..6e80271 100644 --- a/.github/workflows/build_and_test.yaml +++ b/.github/workflows/build_and_test.yaml @@ -17,9 +17,9 @@ jobs: strategy: matrix: include: - - python-version-short: "3.6" - python-version: 3.6.13 - vault-version: 1.5.9 + - python-version-short: "3.8" + python-version: 3.8.17 + vault-version: 1.12.5 steps: - name: Checkout Pack Repo and CI Repos uses: StackStorm-Exchange/ci/.github/actions/checkout@master @@ -99,7 +99,7 @@ jobs: services: mongo: - image: mongo:3.4 + image: mongo:4.4 ports: - 27017:27017 rabbitmq: diff --git a/CHANGES.md b/CHANGES.md index 294adb1..d3f28e8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,9 @@ - Add profile support to pack to define multiple Vault end-points. - Updated README with full list of available actions. - Fixes TLS support for server and client certificates. +- Updated HVAC python module dependency v1.1.0 +- Added token revoke action. +- Updated all actions to use profile name. ## 1.0.0 diff --git a/README.jinja b/README.jinja index 0965451..79c232f 100644 --- a/README.jinja +++ b/README.jinja @@ -77,10 +77,9 @@ The following string sets are available ### Update tactic -The update tactic allows control of how the action will update existing secrets. The currently supported -tactics are: - - `update`: Overwrite an existing secret. - - `abstain`: Do not overwrite an existing secret. +The update tactic controls how the action will update existing secrets. It's intended to ensure idempotence on multiple runs of the secret generation action. The currently supported tactics are: + - `overwrite`: Overwrite an existing secret. + - `refrain`: Do not overwrite an existing secret. ## Sensors {% if sensors | length > 0 %} diff --git a/README.md b/README.md index f3313ce..5286554 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,21 @@ The following options are required to be configured for the pack to work correct The pack provides the following actions: -### delete -_Delete value from Vault server_ +### delete_policy +_Delete policy from Vault server_ | Parameter | Type | Required | Secret | Description | |---|---|---|---|---| -| `path` | string | True | default | _Path to delete from Vault_ | +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `name` | string | True | default | _Policy to delete from Vault_ | +### read_kv +_Read a kv value from Vault server_ +| Parameter | Type | Required | Secret | Description | +|---|---|---|---|---| +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `path` | string | True | default | _Key to read from Vault_ | +| `kv_version` | number | True | default | _The version of the KV store in vault. Use 1 for legacy kv stores, 2 for newer kv stores_ | +| `mount_point` | string | True | default | _The mount point of the kv store_ | +| `version` | string | True | default | _The version of the kv *data*_ | ### generate_secret _Generate a secret and write it to vault._ | Parameter | Type | Required | Secret | Description | @@ -40,58 +50,70 @@ _Generate a secret and write it to vault._ | `update_tactic` | string | False | default | _The logic to use when writing secret to Vault. See readme for details._ | | `string_set` | string | default | default | _Unavailable_ | | `secret_length` | integer | default | default | _The number of characters to use in the secret._ | -### read -_Read value from Vault server_ +### delete +_Delete value from Vault server_ | Parameter | Type | Required | Secret | Description | |---|---|---|---|---| -| `path` | string | True | default | _Key to read from Vault_ | -### create_token -_Create a new Token_ +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `path` | string | True | default | _Path to delete from Vault_ | +### list_policies +_List Policies from Vault server_ | Parameter | Type | Required | Secret | Description | |---|---|---|---|---| -| `token_id` | string | False | default | _Value for the token. By default, this is an auto-generated value._ | -| Items are of type | |||| -| `policies` | array | False | default | _List of policy names to associate with this token._ | -| `meta` | string | False | default | _Metadata to associate with the token. This metadata will show in the audit log when the token is used._ | -| `no_parent` | boolean | False | default | _Unavailable_ | -| `display_name` | string | False | default | _Name to associate with this token. This is a non-sensitive value that can be used to help identify created secrets (e.g. prefixes)._ | -| `num_uses` | string | False | default | _Number of times this token can be used. After the last use, the token is automatically revoked._ | -| `no_default_policy` | boolean | False | default | _Detach the 'default' policy from the policy set for this token._ | -| `ttl` | integer | False | default | _Initial TTL to associate with the token._ | -| `orphan` | boolean | False | default | _Create the token with no parent. This prevents the token from being revoked when the token which created it expires._ | -| `wrap_ttl` | string | False | default | _Unavailable_ | -### write -_Write a key/value to Vault_ +| `profile_name` | string | False | default | _The profile to use to run this action._ | +### is_initialized +_Read initialization status from Vault server_ | Parameter | Type | Required | Secret | Description | |---|---|---|---|---| -| `path` | string | True | default | _Path to the Vault secrets_ | -| `values` | string | True | default | _Keys and values to write in Vault ({"key":"value", "key2": "value2"}_ | -### get_policy -_Read policy from Vault server_ +| `profile_name` | string | False | default | _The profile to use to run this action._ | +### set_policy +_Create a new Vault policy_ | Parameter | Type | Required | Secret | Description | |---|---|---|---|---| -| `name` | string | True | default | _Policy to read from Vault_ | -### delete_policy -_Delete policy from Vault server_ +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `name` | string | True | default | _Name of new Vault Policy_ | +| `rules` | string | True | default | _Policy rules_ | +### read +_Read value from Vault server_ | Parameter | Type | Required | Secret | Description | |---|---|---|---|---| -| `name` | string | True | default | _Policy to delete from Vault_ | -### read_kv -_Read a kv value from Vault server_ +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `path` | string | True | default | _Key to read from Vault_ | +### revoke_token +_Revoke a token and all child tokens._ | Parameter | Type | Required | Secret | Description | |---|---|---|---|---| -| `path` | string | True | default | _Key to read from Vault_ | -| `kv_version` | number | True | default | _The version of the KV store in vault. Use 1 for legacy kv stores, 2 for newer kv stores_ | -| `mount_point` | string | True | default | _The mount point of the kv store_ | -| `version` | string | True | default | _The version of the kv *data*_ | -### set_policy -_Create a new Vault policy_ +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `token` | string | True | default | _Token to revoke._ | +| `mount_point` | string | False | default | _The 'path' the method/backend was mounted on._ | +### get_policy +_Read policy from Vault server_ | Parameter | Type | Required | Secret | Description | |---|---|---|---|---| -| `name` | string | True | default | _Name of new Vault Policy_ | -| `rules` | string | True | default | _Policy rules_ | -### list_policies -_List Policies from Vault server_ +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `name` | string | True | default | _Policy to read from Vault_ | +### create_token +_Create a new Token_ +| Parameter | Type | Required | Secret | Description | +|---|---|---|---|---| +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `token_id` | string | False | default | _The ID of the client token. By default, this is an auto-generated value._ | +| `role_name` | string | False | default | _The name of the token role._ | +| Items are of type | |||| +| `policies` | array | False | default | _List of policy names to associate with this token._ | +| `meta` | string | False | default | _Metadata to associate with the token. This metadata will show in the audit log when the token is used._ | +| `no_parent` | boolean | False | default | _This argument only has effect if used by a root or sudo caller._ | +| `no_default_policy` | boolean | False | default | _Detach the 'default' policy from the policy set for this token._ | +| `renewable` | boolean | False | default | _True: Permit the token to be renewable up to the system/mount maximum TTL. False: Token can't be renewed past its initial TTL._ | +| `ttl` | string | False | default | _Initial TTL to associate with the token, provided as '1h', where hour is the largest suffix. (default unit: seconds)_ | +| `token_type` | string | False | default | _The token type. Can be 'batch' or 'service'. Defaults to the type specified by the role configuration named by role_name._ | +| `explicit_max_ttl` | string | False | default | _If set, the token will never be able to be renewed or used past the value set at issue time._ | +| `display_name` | string | False | default | _Name to associate with this token. This is a non-sensitive value that can be used to help identify created secrets (e.g. prefixes)._ | +| `num_uses` | string | False | default | _Number of times this token can be used. After the last use, the token is automatically revoked._ | +| `period` | string | False | default | _If specified, the token will be periodic; it will have no maximum TTL (unless an 'explicit-max-ttl' is also set) but every renewal will use the given period. Requires a root token or one with the sudo capability._ | +| `entity_alias` | string | default | default | _Name of the entity alias to associate with during token creation._ | +| `wrap_ttl` | string | False | default | _Specifies response wrapping token creation with duration. IE: '15s', '20m', '25h'._ | +| `mount_point` | string | False | default | _The 'path' the method/backend was mounted on._ | ### write_secret _Write a secret to Vault._ | Parameter | Type | Required | Secret | Description | @@ -103,8 +125,13 @@ _Write a secret to Vault._ | `secret` | string | True | True | _Secret contents to be written._ | | `decode_json` | boolean | False | default | _Secret is formatted as a json and should be decode to be sent to Vault_ | | `update_tactic` | string | False | default | _The logic to use when writing secret to Vault. See readme for details._ | -### is_initialized -_Read initialization status from Vault server_ +### write +_Write a key/value to Vault_ +| Parameter | Type | Required | Secret | Description | +|---|---|---|---|---| +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `path` | string | True | default | _Path to the Vault secrets_ | +| `values` | string | True | default | _Keys and values to write in Vault ({"key":"value", "key2": "value2"}_ | @@ -132,10 +159,9 @@ The following string sets are available ### Update tactic -The update tactic allows control of how the action will update existing secrets. The currently supported -tactics are: - - `update`: Overwrite an existing secret. - - `abstain`: Do not overwrite an existing secret. +The update tactic controls how the action will update existing secrets. It's intended to ensure idempotence on multiple runs of the secret generation action. The currently supported tactics are: + - `overwrite`: Overwrite an existing secret. + - `refrain`: Do not overwrite an existing secret. ## Sensors diff --git a/actions/create_token.py b/actions/create_token.py index cb2fa2b..f86673e 100644 --- a/actions/create_token.py +++ b/actions/create_token.py @@ -2,28 +2,48 @@ class VaultCreateTokenAction(action.VaultBaseAction): + """ + Request a child token to be created. Useful for one time use + or fixed time. + """ + def run( self, - token_id=None, - policies=None, + display_name=None, + entity_alias=None, + explicit_max_ttl="1h", meta=None, + mount_point="token", + no_default_policy=False, no_parent=False, - display_name=None, num_uses=None, - no_default_policy=False, + period=None, + policies=None, + profile_name=None, + renewable=True, + role_name=None, + token_id=None, + token_type=None, ttl=None, - orphan=False, wrap_ttl=None, ): - return self.vault.create_token( - token_id=token_id, - policies=policies, + super().run(profile_name=profile_name) + + return self.vault.auth.token.create( + display_name=display_name, + entity_alias=entity_alias, + explicit_max_ttl=explicit_max_ttl, + id=token_id, meta=meta, + mount_point=mount_point, + no_default_policy=no_default_policy, no_parent=no_parent, - display_name=display_name, num_uses=num_uses, - no_default_policy=no_default_policy, + period=period, + policies=policies, + renewable=renewable, + role_name=role_name, ttl=ttl, - orphan=orphan, + type=token_type, wrap_ttl=wrap_ttl, ) diff --git a/actions/create_token.yaml b/actions/create_token.yaml index 7c467d3..1745359 100644 --- a/actions/create_token.yaml +++ b/actions/create_token.yaml @@ -6,9 +6,17 @@ description: "Create a new Token" enabled: true entry_point: "create_token.py" parameters: + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false token_id: type: string - description: "Value for the token. By default, this is an auto-generated value." + description: "The ID of the client token. By default, this is an auto-generated value." + required: false + role_name: + type: string + description: "The name of the token role." required: false policies: type: array @@ -22,9 +30,31 @@ parameters: description: "Metadata to associate with the token. This metadata will show in the audit log when the token is used." required: false no_parent: + description: "This argument only has effect if used by a root or sudo caller." + type: boolean + required: false + default: false + no_default_policy: type: boolean + description: "Detach the 'default' policy from the policy set for this token." required: false default: false + renewable: + type: boolean + description: "True: Permit the token to be renewable up to the system/mount maximum TTL. False: Token can't be renewed past its initial TTL." + required: false + ttl: + type: string + description: "Initial TTL to associate with the token, provided as '1h', where hour is the largest suffix. (default unit: seconds)" + required: false + token_type: + type: string + description: "The token type. Can be 'batch' or 'service'. Defaults to the type specified by the role configuration named by role_name." + required: false + explicit_max_ttl: + type: string + description: "If set, the token will never be able to be renewed or used past the value set at issue time." + required: false display_name: type: string description: "Name to associate with this token. This is a non-sensitive value that can be used to help identify created secrets (e.g. prefixes)." @@ -33,20 +63,18 @@ parameters: type: string description: "Number of times this token can be used. After the last use, the token is automatically revoked." required: false - no_default_policy: - type: boolean - description: "Detach the 'default' policy from the policy set for this token." - required: false - default: false - ttl: - type: integer - description: "Initial TTL to associate with the token." - required: false - orphan: - type: boolean - description: "Create the token with no parent. This prevents the token from being revoked when the token which created it expires." + period: + type: string + description: "If specified, the token will be periodic; it will have no maximum TTL (unless an 'explicit-max-ttl' is also set) but every renewal will use the given period. Requires a root token or one with the sudo capability." required: false - default: false + entity_alias: + type: string + description: "Name of the entity alias to associate with during token creation." wrap_ttl: type: string + description: "Specifies response wrapping token creation with duration. IE: '15s', '20m', '25h'." + required: false + mount_point: + type: string + description: "The 'path' the method/backend was mounted on." required: false diff --git a/actions/delete.py b/actions/delete.py index ebf2050..c59fb94 100644 --- a/actions/delete.py +++ b/actions/delete.py @@ -2,5 +2,9 @@ class VaultDeleteAction(action.VaultBaseAction): - def run(self, path): + """ + Delete a v1 path. + """ + def run(self, path, profile_name=None): + super().run(profile_name=profile_name) return self.vault.delete(path) diff --git a/actions/delete.yaml b/actions/delete.yaml index 649da18..c95de82 100644 --- a/actions/delete.yaml +++ b/actions/delete.yaml @@ -5,8 +5,12 @@ description: "Delete value from Vault server" enabled: true entry_point: "delete.py" parameters: - path: - type: string - description: "Path to delete from Vault" - required: true - position: 0 + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false + path: + type: string + description: "Path to delete from Vault" + required: true + position: 0 diff --git a/actions/delete_policy.py b/actions/delete_policy.py index b969a4b..d7472d0 100644 --- a/actions/delete_policy.py +++ b/actions/delete_policy.py @@ -2,5 +2,6 @@ class VaultPolicyDeleteAction(action.VaultBaseAction): - def run(self, name): + def run(self, name, profile_name=None): + super().run(profile_name=profile_name) return self.vault.sys.delete_policy(name) diff --git a/actions/delete_policy.yaml b/actions/delete_policy.yaml index d0f3211..ea0b61f 100644 --- a/actions/delete_policy.yaml +++ b/actions/delete_policy.yaml @@ -6,8 +6,12 @@ description: "Delete policy from Vault server" enabled: true entry_point: "delete_policy.py" parameters: - name: - type: string - description: "Policy to delete from Vault" - required: true - position: 0 + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false + name: + type: string + description: "Policy to delete from Vault" + required: true + position: 0 diff --git a/actions/generate_secret.yaml b/actions/generate_secret.yaml index 2981440..438963e 100644 --- a/actions/generate_secret.yaml +++ b/actions/generate_secret.yaml @@ -14,22 +14,25 @@ parameters: description: Vault moint point in the URL required: false default: "/" + position: 0 path: type: string description: "Path to the secrets" required: true + position: 1 key_name: type: string description: "Name of the key to write the secret." required: true + position: 2 update_tactic: type: string description: "The logic to use when writing secret to Vault. See readme for details." required: false enum: - - "update" - - "abstain" - default: "abstain" + - "overwrite" + - "refrain" + default: "refrain" string_set: type: string enum: diff --git a/actions/get_policy.py b/actions/get_policy.py index 8dbcef6..ea0ff32 100644 --- a/actions/get_policy.py +++ b/actions/get_policy.py @@ -2,5 +2,6 @@ class VaultGetPolicyAction(action.VaultBaseAction): - def run(self, name): + def run(self, name, profile_name=None): + super().run(profile_name=profile_name) return self.vault.get_policy(name) diff --git a/actions/get_policy.yaml b/actions/get_policy.yaml index b515ff4..efa3eb5 100644 --- a/actions/get_policy.yaml +++ b/actions/get_policy.yaml @@ -6,8 +6,12 @@ description: "Read policy from Vault server" enabled: true entry_point: "get_policy.py" parameters: - name: - type: string - description: "Policy to read from Vault" - required: true - position: 0 + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false + name: + type: string + description: "Policy to read from Vault" + required: true + position: 0 diff --git a/actions/is_initialized.py b/actions/is_initialized.py index 25d8f8f..7eab728 100644 --- a/actions/is_initialized.py +++ b/actions/is_initialized.py @@ -2,5 +2,6 @@ class VaultIsInitializedAction(action.VaultBaseAction): - def run(self): - return self.vault.sys.is_initialized() + def run(self, profile_name=None): + super().run(profile_name=profile_name) + return (True, {"initialised": self.vault.sys.is_initialized()}) diff --git a/actions/is_initialized.yaml b/actions/is_initialized.yaml index d14ab15..2fb7d50 100644 --- a/actions/is_initialized.yaml +++ b/actions/is_initialized.yaml @@ -4,3 +4,8 @@ runner_type: python-script description: "Read initialization status from Vault server" enabled: true entry_point: "is_initialized.py" +parameters: + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false diff --git a/actions/lib/action.py b/actions/lib/action.py index 3dfe038..cac2808 100644 --- a/actions/lib/action.py +++ b/actions/lib/action.py @@ -19,14 +19,14 @@ def run(self, profile_name=None): if profile_name is None: profile_name = self.config.get("default_profile") if profile_name is None: - raise Exception("No default profile found, check the pack configuration.") + raise ValueError("No default profile found, check the pack configuration.") for profile in self.config.get("profiles", []): if profile_name == profile["name"]: self._configure_client(profile) break else: - raise Exception( + raise ValueError( f"Profile '{profile_name}' doesn't exist, check the pack configuration." ) @@ -47,7 +47,7 @@ def _configure_client(self, profile): # Client certificate cert = (profile.get("client_cert_path"), profile.get("client_key_path")) if bool(cert[0]) ^ bool(cert[1]): - raise Exception( + raise ValueError( "Client-side TLS requires the certificate and key, check the pack configuration." ) @@ -60,13 +60,13 @@ def _configure_client(self, profile): # Use the configured authentication method to acquire the token. auth_method = profile.get("auth_method") if auth_method not in auth_methods: - raise Exception(f"Auth method '{auth_method}' is not supported.") + raise ValueError(f"Auth method '{auth_method}' is not supported.") # Authenticate the client connection. auth_methods[auth_method](profile) if self.vault.token is None: - raise Exception( + raise ValueError( "Failed to set a valid token for the client, check the pack configuration." ) diff --git a/actions/list_policies.py b/actions/list_policies.py index 2e7dab5..864a6eb 100644 --- a/actions/list_policies.py +++ b/actions/list_policies.py @@ -2,5 +2,6 @@ class VaultPolicyListAction(action.VaultBaseAction): - def run(self): - return self.vault.list_policies() + def run(self, profile_name=None): + super().run(profile_name=profile_name) + return (True, {"policies": self.vault.sys.list_policies()}) diff --git a/actions/list_policies.yaml b/actions/list_policies.yaml index 57886cf..6c455a0 100644 --- a/actions/list_policies.yaml +++ b/actions/list_policies.yaml @@ -4,3 +4,8 @@ runner_type: python-script description: "List Policies from Vault server" enabled: true entry_point: "list_policies.py" +parameters: + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false diff --git a/actions/read.py b/actions/read.py index ecb5987..87e4a60 100644 --- a/actions/read.py +++ b/actions/read.py @@ -2,9 +2,10 @@ class VaultReadAction(action.VaultBaseAction): - def run(self, path): + def run(self, path, profile_name=None): + super().run(profile_name=profile_name) value = self.vault.read(path) if value: - return value["data"] - else: - raise KeyError("Key was not found in Vault") + return (True, value["data"]) + + return (False, f"Key was not found in path {path}") diff --git a/actions/read.yaml b/actions/read.yaml index c9a2f80..caedcc7 100644 --- a/actions/read.yaml +++ b/actions/read.yaml @@ -5,8 +5,12 @@ description: "Read value from Vault server" enabled: true entry_point: "read.py" parameters: - path: - type: string - description: "Key to read from Vault" - required: true - position: 0 + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false + path: + type: string + description: "Key to read from Vault" + required: true + position: 0 diff --git a/actions/read_kv.py b/actions/read_kv.py index 35f739d..38c1910 100644 --- a/actions/read_kv.py +++ b/actions/read_kv.py @@ -2,19 +2,21 @@ class VaultReadKVAction(action.VaultBaseAction): - def run(self, path, kv_version, mount_point, version, profile=None): - super().run(profile_name=profile) + def run(self, path, kv_version, mount_point, version, profile_name=None): + super().run(profile_name=profile_name) value = None - if kv_version == 1: + if kv_version == "1": value = self.vault.secrets.kv.v1.read_secret(path=path, mount_point=mount_point) - elif kv_version == 2: + elif kv_version == "2": value = self.vault.secrets.kv.v2.read_secret_version( path=path, mount_point=mount_point, version=version ) + else: + return (False, f"Unsupported kv version {kv_version}.") if value: - return value["data"] - else: - raise KeyError("Key was not found in Vault") + return (True, value) + + return (False, f"Secret was not found at mount: {mount}, path: {path}") diff --git a/actions/read_kv.yaml b/actions/read_kv.yaml index cf3b423..4d98b3a 100644 --- a/actions/read_kv.yaml +++ b/actions/read_kv.yaml @@ -5,22 +5,29 @@ description: "Read a kv value from Vault server" enabled: true entry_point: "read_kv.py" parameters: - path: - type: string - description: "Key to read from Vault" - required: true - position: 0 - kv_version: - type: number - description: "The version of the KV store in vault. Use 1 for legacy kv stores, 2 for newer kv stores" - required: true - mount_point: - type: string - description: "The mount point of the kv store" - required: true - default: "secret" - version: - type: string - description: "The version of the kv *data*" - required: true - default: '1' + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false + path: + type: string + description: "Key to read from Vault" + required: true + position: 0 + kv_version: + type: number + description: "The version of the KV store in vault. Use 1 for legacy kv stores, 2 for newer kv stores" + required: true + position: 1 + mount_point: + type: string + description: "The mount point of the kv store" + required: true + default: "secret" + position: 2 + version: + type: string + description: "The version of the kv *data*" + required: true + default: "1" + position: 3 diff --git a/actions/revoke_token.py b/actions/revoke_token.py new file mode 100644 index 0000000..e1b98dc --- /dev/null +++ b/actions/revoke_token.py @@ -0,0 +1,17 @@ +from lib import action + + +class VaultRevokeTokenAction(action.VaultBaseAction): + """ + Revoke a token and all child tokens. + + When the token is revoked, all dynamic secrets generated with it are also revoked. + """ + + def run(self, token, profile_name=None, mount_point="token"): + super().run(profile_name=profile_name) + + return self.vault.auth.token.revoke( + token=token, + mount_point=mount_point, + ) diff --git a/actions/revoke_token.yaml b/actions/revoke_token.yaml new file mode 100644 index 0000000..7e6f537 --- /dev/null +++ b/actions/revoke_token.yaml @@ -0,0 +1,21 @@ +--- +name: revoke_token +pack: vault +runner_type: python-script +description: "Revoke a token and all child tokens." +enabled: true +entry_point: "revoke_token.py" +parameters: + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false + token: + description: "Token to revoke." + type: "string" + required: true + position: 0 + mount_point: + description: "The 'path' the method/backend was mounted on." + type: "string" + required: false diff --git a/actions/set_policy.py b/actions/set_policy.py index d570fb5..4b1332a 100644 --- a/actions/set_policy.py +++ b/actions/set_policy.py @@ -2,5 +2,6 @@ class VaultPolicySetAction(action.VaultBaseAction): - def run(self, name, rules): + def run(self, name, rules, profile_name=None): + super().run(profile_name=profile_name) return self.vault.sys.create_or_update_policy(name, rules) diff --git a/actions/set_policy.yaml b/actions/set_policy.yaml index 115f7d4..4c5e495 100644 --- a/actions/set_policy.yaml +++ b/actions/set_policy.yaml @@ -6,13 +6,17 @@ description: "Create a new Vault policy" enabled: true entry_point: "set_policy.py" parameters: - name: - type: string - description: "Name of new Vault Policy" - required: true - position: 0 - rules: - type: string - description: "Policy rules" - required: true - position: 1 + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false + name: + type: string + description: "Name of new Vault Policy" + required: true + position: 0 + rules: + type: string + description: "Policy rules" + required: true + position: 1 diff --git a/actions/write.py b/actions/write.py index f5dbabd..9e2a2b8 100644 --- a/actions/write.py +++ b/actions/write.py @@ -3,5 +3,6 @@ class VaultWriteAction(action.VaultBaseAction): - def run(self, path, values): + def run(self, path, values, profile_name=None): + super().run(profile_name=profile_name) return self.vault.write(path, **json.loads(values)) diff --git a/actions/write.yaml b/actions/write.yaml index 7fab7c2..cec0ce6 100644 --- a/actions/write.yaml +++ b/actions/write.yaml @@ -5,13 +5,17 @@ description: "Write a key/value to Vault" enabled: true entry_point: "write.py" parameters: - path: - type: string - description: "Path to the Vault secrets" - required: true - position: 0 - values: - type: string - description: 'Keys and values to write in Vault ({"key":"value", "key2": "value2"}' - required: true - position: 1 + profile_name: + description: "The profile to use to run this action." + type: "string" + required: false + path: + type: string + description: "Path to the Vault secrets" + required: true + position: 0 + values: + type: string + description: 'Keys and values to write in Vault ({"key":"value", "key2": "value2"}' + required: true + position: 1 diff --git a/actions/write_secret.py b/actions/write_secret.py index ab9b9b3..a7dd9e6 100644 --- a/actions/write_secret.py +++ b/actions/write_secret.py @@ -16,7 +16,7 @@ def generate_secret(string_set="ascii_letters", length=8): """ Retrun a random string. """ - if not (0 < length < 256): + if not 0 < length < 256: raise ValueError("Secret length must be between 1 and 255 characters.") if string_set not in [ "ascii_letters", @@ -70,18 +70,17 @@ class VaultGenerateSecretAction(action.VaultBaseAction): def run( self, - profile_name, mount_point, path, key_name, - update_tactic, + update_tactic="refrain", + profile_name=None, secret=None, decode_json=False, string_set=None, secret_length=None, - eng_ver="v1", ): - super().run(profile_name) + super().run(profile_name=profile_name) if string_set and secret_length: secret = generate_secret(string_set, secret_length) @@ -92,25 +91,25 @@ def run( " secret_length parameters to generate a secret." ) - if update_tactic not in ["abstain", "update"]: + if update_tactic not in ["refrain", "overwrite"]: raise ValueError(f"Unknown update tactic '{update_tactic}'") current_secret = read_secret(self.vault, mount_point, path) - if update_tactic == "abstain" and key_name in current_secret.keys(): - write_ok = False - msg = f"Abstained from updating existing secret {mount_point}/{path}" + if update_tactic == "refrain" and key_name in current_secret.keys(): + allow_overwrite = False + msg = f"Refrain from updating existing secret {mount_point}/{path}" else: - write_ok = True + allow_overwrite = True - if write_ok: + if allow_overwrite: if decode_json: secret = json.loads(secret) current_secret.update({key_name: secret}) - r = write_secret(self.vault, mount_point, path, current_secret) - if r.ok: + write_result = write_secret(self.vault, mount_point, path, current_secret) + if write_result.ok: msg = f"Wrote secret {key_name} to {mount_point}/{path}" else: - write_ok = r.ok - msg = r.reason + allow_overwrite = write_result.ok + msg = write_result.reason - return (True, {"updated": write_ok, "message": msg}) + return (True, {"updated": allow_overwrite, "message": msg}) diff --git a/actions/write_secret.yaml b/actions/write_secret.yaml index 2e92072..317cb21 100644 --- a/actions/write_secret.yaml +++ b/actions/write_secret.yaml @@ -14,14 +14,17 @@ parameters: description: Vault moint point in the URL required: false default: "/" + position: 0 path: type: string description: "Path to the secrets" required: true + position: 1 key_name: type: string description: "Name of the key to write the secret." required: true + position: 2 secret: type: string description: "Secret contents to be written." @@ -37,6 +40,6 @@ parameters: description: "The logic to use when writing secret to Vault. See readme for details." required: false enum: - - "update" - - "abstain" - default: "abstain" + - "overwrite" + - "refrain" + default: "refrain" diff --git a/requirements-tests.txt b/requirements-tests.txt index 2d2fb9a..591aeed 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -1,2 +1 @@ -# do we need parser (pyhcl) for the actions as well or just tests? hvac[parser] diff --git a/requirements.txt b/requirements.txt index c02773e..987f83a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -hvac>=0.10.6 +hvac>=1.1.0