Skip to content

Commit

Permalink
Minor fixes and improvements (#54)
Browse files Browse the repository at this point in the history
* Ignore config.yaml for testing purposes

* Add info about using a custom CA

* Allow empty token auth to use defaults

* Stop use deprecated method for K8S login, set the mount point correctly and set the role

* Bump version: 1.0.9 → 1.0.10

* Only ignore empty auth types if set to none, watch for empty dicts

* Missed auth

* Update the README

* Handle leading slashes and whole mountpoints

* Remove old print statement

* Handle leading slashes and whole mountpoints

* Fix kubernetes auth test
  • Loading branch information
eugene-davis authored Jul 6, 2022
1 parent 4d98d19 commit 202f51d
Show file tree
Hide file tree
Showing 11 changed files with 34 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.0.9
current_version = 1.0.10
commit = True
tag = False
message = Bump version: {current_version} → {new_version}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
workflow_dispatch:

env:
VERSION: 1.0.9
VERSION: 1.0.10

jobs:
release:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,6 @@ dmypy.json

# Pyre type checker
.pyre/

# Config file
config.yaml
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,19 @@ The schema for the configuration can be shown with `start_exporter --show_schema
* `namespace` - the namespace to use for the Vault server, for root namespace or for open source instances, leave blank
* `authentication` - contains the authentication configuration for accessing Hashicorp Vault, see the "Configuring Authentication" section

#### Using a Custom CA

For using a custom CA (or otherwise setting the trusted certificate authorities) please use the environmental variable `REQUESTS_CA_BUNDLE`.

See the [requests documentation](https://requests.readthedocs.io/en/latest/user/advanced/#ssl-cert-verification) for more details.

##### Configuring Authentication

There are currently three supported authentication methods: `token`, `approle` and `kubernetes`.
All of these require that an appropriate policy is bound to the resulting `token`, the permissions for which are described in each of the module READMEs.

If you wish to use the defaults for any authentication type, you can simply use `{}` after specifying it, e.g. `kubernetes: {}`.

##### Token Authentication

Token authentication is not generally recommended for production deployments, but rather for testing and development.
Expand Down Expand Up @@ -98,6 +106,7 @@ Kubernetes configuration allows using the `jwt` token provided by a Kuberenetes

* `token_file` - path to the token file, defaults to /var/run/secrets/kubernetes.io/serviceaccount/token
* `mount_point` - mount point in Vault for the kubernetes authentication to use, `kubernetes` by default
* `role` - the role in the kubernetes authentication method to use, `vape` by default

## Modules

Expand Down
6 changes: 3 additions & 3 deletions docs/CONFIGURATION_EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ At a bare minimum, Vault must be configured with an address and some authenticat
vault:
address: https://vault.exampledomainname.com
authentication:
token:
token: {}
```
## Complete Simple Configuration using Token Authentication for Expiration Monitoring
An example of the absolute bare minimum configuration to monitor a single secret.
An example of the absolute bare minimum configuration to monitor a single secret using the kubernetes authentication option with defaults.
```yaml
vault:
address: https://vault.exampledomainname.com
authentication:
token:
kubernetes: {}

expiration_monitoring:
services:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "vault-assessment-prometheus-exporter"
version = "1.0.9"
version = "1.0.10"
description = "Prometheus exporter to monitor custom metadata for KV2 secrets for (self-imposed) expiration."
authors = ["Eugene Davis <[email protected]>"]
readme = "README.md"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_vault_authenticate.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def test_get_client_with_kubernetes_auth(mocker):
vault_monitor.common.vault_authenticate.get_client_with_kubernetes_auth(config=test_config, address=test_address, namespace=test_namespace)

mock_get_client.assert_called_once_with(url=test_address, namespace=test_namespace)
mock_client.auth_kubernetes.assert_called_once_with("kubernetes", "test_kubernetes_token")
mock_client.auth.kubernetes.login.assert_called_once_with("vape", "test_kubernetes_token", mount_point="kubernetes")


@mock.patch.dict(os.environ, {"VAULT_TOKEN": "test_token"})
Expand Down
9 changes: 6 additions & 3 deletions vault_monitor/common/vault_authenticate.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ def get_authenticated_client(auth_config: Dict[str, Dict[str, str]], address: st
kubernetes_auth_config = auth_config.get("kubernetes", None)
token_auth_config = auth_config.get("token", {})

if approle_auth_config:
if approle_auth_config is not None:
return get_client_with_approle_auth(approle_auth_config, address, namespace)

if kubernetes_auth_config:
if kubernetes_auth_config is not None:
return get_client_with_kubernetes_auth(kubernetes_auth_config, address, namespace)

# As a last ditch effort check for tokens, this includes checking for sensible defaults in case of limited configuration
if token_auth_config is None:
token_auth_config = {}
return get_client_with_token_auth(token_auth_config, address, namespace)


Expand Down Expand Up @@ -114,11 +116,12 @@ def get_client_with_kubernetes_auth(config: Dict[str, str], address: str, namesp
Returns an authenticated Vault client with Kuberenetes authentication.
"""
mount_point = config.get("mount_point", "kubernetes")
role = config.get("role", "vape")
jwt_file_path = config.get("token_file", "/var/run/secrets/kubernetes.io/serviceaccount/token")
with open(jwt_file_path, "r", encoding="UTF8") as jwt_file:
jwt = jwt_file.read()
client = hvac.Client(url=address, namespace=namespace)
client.auth_kubernetes(mount_point, jwt)
client.auth.kubernetes.login(role, jwt, mount_point=mount_point)
return client


Expand Down
10 changes: 7 additions & 3 deletions vault_monitor/expiration_monitor/create_monitors.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,13 @@ def create_monitors(config: Dict, vault_client: hvac_client) -> Sequence[Expirat
if not secret.get("recursive", False):
secret_paths.append(secret.get("secret_path"))
else:
secret_paths = recurse_secrets(mount_point=secret.get("mount_point"), secret_path=secret.get("secret_path"), vault_client=vault_client)
secret_path = secret.get("secret_path")
# Remove any forward slashes at the beginning of the secret path
secret_path = secret_path[1:] if secret_path and secret_path[0] == "/" else secret_path
secret_paths = recurse_secrets(mount_point=secret.get("mount_point"), secret_path=secret_path, vault_client=vault_client)

for secret_path in secret_paths:
LOGGER.debug("Monitoring %s/%s", secret.get("mount_point"), secret.get("secret_path"))
LOGGER.debug("Monitoring %s/%s", secret.get("mount_point"), secret_path)
secret_monitor = SecretExpirationMonitor(
secret.get("mount_point"),
secret_path,
Expand Down Expand Up @@ -75,7 +78,8 @@ def recurse_secrets(mount_point: str, secret_path: str, vault_client: hvac_clien
for key in keys:
# Check if the key is a "directory"
if key[-1] == "/":
secrets += recurse_secrets(mount_point=mount_point, secret_path=f"{secret_path}/{key[:-1]}", vault_client=vault_client)
subpath = f"{secret_path}/{key[:-1]}" if secret_path else key[:-1]
secrets += recurse_secrets(mount_point=mount_point, secret_path=subpath, vault_client=vault_client)
else:
secrets.append(f"{secret_path}/{key}")

Expand Down
1 change: 0 additions & 1 deletion vault_monitor/expiration_monitor/expiration_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ def create_metrics(cls: Type[ExpirationMonitorType], prometheus_label_keys: List
"""
# Only create the metric once
if not hasattr(cls, "secret_last_renewal_timestamp_gauge"):
print(prometheus_label_keys)
cls.secret_last_renewal_timestamp_gauge = Gauge(cls.last_renewal_gauge_name, cls.last_renewal_gauge_description, prometheus_label_keys)
if not hasattr(cls, "secret_expiration_timestamp_gauge"):
cls.secret_expiration_timestamp_gauge = Gauge(cls.expiration_gauge_name, cls.expiration_gauge_description, prometheus_label_keys)
Expand Down
6 changes: 2 additions & 4 deletions vault_monitor/scripts/start_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def get_config_schema(modules: List) -> Dict[str, Dict]:
{
"token": {
"type": "dict",
"nullable": True,
"schema": {
"token_var_name": {"type": "string", "nullable": True},
"token_file": {"type": "string", "nullable": True},
Expand All @@ -173,10 +174,7 @@ def get_config_schema(modules: List) -> Dict[str, Dict]:
"kubernetes": {
"type": "dict",
"nullable": True,
"schema": {
"token_file": {"type": "string", "nullable": True},
"mount_point": {"type": "string", "nullable": True},
},
"schema": {"token_file": {"type": "string", "nullable": True}, "mount_point": {"type": "string", "nullable": True}, "role": {"type": "string", "nullable": True}},
"meta": {"description": "Configuration for Kubernetes authentication method.", "link": "https://www.vaultproject.io/docs/auth/kubernetes"},
}
},
Expand Down

0 comments on commit 202f51d

Please sign in to comment.