From 06bfb518e3e5c2a2de0ff36457427cb8a810c94e Mon Sep 17 00:00:00 2001 From: Carlos Date: Tue, 7 Jun 2022 16:38:36 +0200 Subject: [PATCH] Update readme to include generate secret action. --- CHANGES.md | 9 +++++- README.jinja | 9 ------ README.md | 65 +++++++++++++++++++++++++++++++++++------ actions/lib/action.py | 17 +++++++---- actions/read_kv.py | 6 ++-- actions/write_secret.py | 35 +++++++++++----------- pack.yaml | 2 +- 7 files changed, 95 insertions(+), 48 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e04305a..294adb1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,8 +1,15 @@ # Change Log +## 2.0.0 + +- Add action to generate secrets. +- 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. + ## 1.0.0 -* Drop Python 2.7 support +- Drop Python 2.7 support ## 0.6.0 diff --git a/README.jinja b/README.jinja index e6fc1a9..0965451 100644 --- a/README.jinja +++ b/README.jinja @@ -1,13 +1,6 @@ # {{ pack["pack.yaml"].name }} integration pack _{{ pack["pack.yaml"].description }}_ -{{ pack["pack.yaml"].author }} <{{ pack["pack.yaml"].email }}> - -### Contributors -{% for contributor in pack["pack.yaml"].contributors -%} - - {{ contributor }} -{% endfor %} - {% if pack and pack["config.schema.yaml"] -%} ## Configuration @@ -81,8 +74,6 @@ The following string sets are available ```0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c``` - alphanumeric ```abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789``` - - alphanumeric - ```abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789``` ### Update tactic diff --git a/README.md b/README.md index 15b2309..f3313ce 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,5 @@ # vault integration pack - -> HashiCorp Vault -steve.neuharth - -### Contributors -- Andy Moore -- Jacob Floyd - +_HashiCorp Vault_ ## Configuration @@ -36,6 +29,17 @@ _Delete value from Vault server_ | Parameter | Type | Required | Secret | Description | |---|---|---|---|---| | `path` | string | True | default | _Path to delete from Vault_ | +### generate_secret +_Generate a secret and write it to vault._ +| Parameter | Type | Required | Secret | Description | +|---|---|---|---|---| +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `mount_point` | string | False | default | _Vault moint point in the URL_ | +| `path` | string | True | default | _Path to the secrets_ | +| `key_name` | string | True | default | _Name of the key to write the secret._ | +| `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_ | Parameter | Type | Required | Secret | Description | @@ -49,7 +53,7 @@ _Create a new Token_ | 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 | __ | +| `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._ | @@ -88,11 +92,51 @@ _Create a new Vault policy_ | `rules` | string | True | default | _Policy rules_ | ### list_policies _List Policies from Vault server_ +### write_secret +_Write a secret to Vault._ +| Parameter | Type | Required | Secret | Description | +|---|---|---|---|---| +| `profile_name` | string | False | default | _The profile to use to run this action._ | +| `mount_point` | string | False | default | _Vault moint point in the URL_ | +| `path` | string | True | default | _Path to the secrets_ | +| `key_name` | string | True | default | _Name of the key to write the secret._ | +| `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_ + +### generate secret + +This action is written to pre-populate keys with a random secret. + +The following string sets are available + + - ascii_letters + ```abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ``` + - ascii_lowercase + ```abcdefghijklmnopqrstuvwxyz``` + - ascii_uppercase + ```ABCDEFGHIJKLMNOPQRSTUVWXYZ``` + - digits + ```0123456789``` + - punctuation + ```!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~``` + - printable + ```0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c``` + - alphanumeric + ```abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789``` + +### 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. + ## Sensors There are no sensors available for this pack. @@ -100,6 +144,9 @@ There are no sensors available for this pack. ## Authentication methods +Authentication methods are defined per profile and are mutally exclusive. Only configure the +method that should be used. + ### Supported - approle - token diff --git a/actions/lib/action.py b/actions/lib/action.py index cfc2c17..3dfe038 100644 --- a/actions/lib/action.py +++ b/actions/lib/action.py @@ -3,6 +3,10 @@ class VaultBaseAction(Action): + """ + Base Action includes st2 profile and vault client functions + for child classes. + """ def __init__(self, config): super().__init__(config) self.config = config @@ -17,9 +21,9 @@ def run(self, profile_name=None): if profile_name is None: raise Exception("No default profile found, check the pack configuration.") - for p in self.config.get("profiles", []): - if profile_name == p["name"]: - self._configure_client(p) + for profile in self.config.get("profiles", []): + if profile_name == profile["name"]: + self._configure_client(profile) break else: raise Exception( @@ -44,9 +48,10 @@ def _configure_client(self, profile): cert = (profile.get("client_cert_path"), profile.get("client_key_path")) if bool(cert[0]) ^ bool(cert[1]): raise Exception( - f"Client-side TLS requires the certificate and key, check the pack configuration" + "Client-side TLS requires the certificate and key, check the pack configuration." ) - elif cert[0] and cert[1]: + + if cert[0] and cert[1]: client_kwargs["cert"] = cert # Create a connection to vault @@ -62,7 +67,7 @@ def _configure_client(self, profile): if self.vault.token is None: raise Exception( - f"Failed to set a valid token for the client, check the pack configuration." + "Failed to set a valid token for the client, check the pack configuration." ) def _auth_token(self, profile): diff --git a/actions/read_kv.py b/actions/read_kv.py index ee14196..35f739d 100644 --- a/actions/read_kv.py +++ b/actions/read_kv.py @@ -8,15 +8,13 @@ def run(self, path, kv_version, mount_point, version, profile=None): value = None if kv_version == 1: - value = self.vault.secrets.kv.v1.read_secret( - path=path, mount_point=mount_point - ) + value = self.vault.secrets.kv.v1.read_secret(path=path, mount_point=mount_point) elif kv_version == 2: value = self.vault.secrets.kv.v2.read_secret_version( path=path, mount_point=mount_point, version=version ) if value: - return value['data'] + return value["data"] else: raise KeyError("Key was not found in Vault") diff --git a/actions/write_secret.py b/actions/write_secret.py index 7adce5b..ab9b9b3 100644 --- a/actions/write_secret.py +++ b/actions/write_secret.py @@ -32,10 +32,13 @@ def generate_secret(string_set="ascii_letters", length=8): def read_secret(client, mount_point, path): + """ + Read secret from Vault and return it. + """ try: tmp = client.secrets.kv.v1.read_secret(path=path, mount_point=mount_point) res = tmp.get("data", {}) - except hvac.exceptions.InvalidPath as e: + except hvac.exceptions.InvalidPath: res = {} return res @@ -89,29 +92,25 @@ def run( " secret_length parameters to generate a secret." ) - if update_tactic == "abstain": - r = read_secret(self.vault, mount_point, path) - if key_name in r.keys(): - write_ok = False - msg = f"Abstained from updating existing secret {mount_point}/{path}" - else: - write_ok = True - res = r - elif update_tactic == "update": - write_ok = True - res = read_secret(self.vault, mount_point, path) - else: + if update_tactic not in ["abstain", "update"]: 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}" + else: + write_ok = True + if write_ok: if decode_json: secret = json.loads(secret) - res.update({key_name: secret}) - r = write_secret(self.vault, mount_point, path, res) - if not r.ok: + current_secret.update({key_name: secret}) + r = write_secret(self.vault, mount_point, path, current_secret) + if r.ok: + msg = f"Wrote secret {key_name} to {mount_point}/{path}" + else: write_ok = r.ok msg = r.reason - else: - msg = f"Written secret {key_name} to {mount_point}/{path}" return (True, {"updated": write_ok, "message": msg}) diff --git a/pack.yaml b/pack.yaml index 48ddb9c..886146f 100644 --- a/pack.yaml +++ b/pack.yaml @@ -2,7 +2,7 @@ ref: vault name: vault description: HashiCorp Vault -version: 1.0.0 +version: 2.0.0 python_versions: - "3" author: steve.neuharth