Skip to content

Commit

Permalink
Merge pull request #198 from peopledoc/templates
Browse files Browse the repository at this point in the history
  • Loading branch information
Joachim Jablon committed Dec 15, 2021
2 parents fbde0c3 + 2abe845 commit 3ba3955
Show file tree
Hide file tree
Showing 13 changed files with 41 additions and 350 deletions.
1 change: 0 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ Some features
- Launch processes with your secrets as environment variables
- Launch processes with ``ssh-agent`` configured from your vault
- Write templated files with secrets inside
- Combine multiple secrets into a single one (e.g. a DSN string from components)

``vault-cli`` tries to make accessing secrets both secure and painless.

Expand Down
5 changes: 0 additions & 5 deletions docs/howto/environment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,3 @@ even if it will be missing some secrets.
.. code:: console
$ vault-cli env --envvar myapp --force -- myapp
.. warning::

Even if just a single key for a secret produces an error (e.g. a template rendering
error), the whole secret will be missing.
8 changes: 0 additions & 8 deletions docs/howto/systemd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,6 @@ Vault-cli aims at helping you launch your application with the secrets
it needs without writing them on disk. This page lists a few scenarios
that may be useful.

If the value you need to pass is directly a secret that is stored in the
vault, perfect. Otherwise, you may want to create a `templated
value`__
to recreate your secret value by combining static strings and other
secrets.

.. __: https://github.com/peopledoc/vault-cli/#create-a-templated-value

Let’s assume the value you need to pass is the value you get with:

.. code:: console
Expand Down
84 changes: 0 additions & 84 deletions docs/howto/templated_secrets.rst

This file was deleted.

8 changes: 8 additions & 0 deletions docs/howto/upgrade.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Upgrade ``vault-cli`` from previous version
===========================================

From 2.x to 3.x
~~~~~~~~~~~~~~~

Templated values (``!template!{{ vault("a").b }}``) aren't supported anymore.
If you were using those, you will get a warning starting on ``vault-cli~=2.2.1``.

On 3.x, a ``--render/--no-render`` flag is still available but it does nothing.

From 1.x to 2.x
~~~~~~~~~~~~~~~

Expand Down
1 change: 0 additions & 1 deletion docs/howto_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ How-to...
howto/write
howto/environment
howto/template
howto/templated_secrets
howto/ssh
howto/systemd
howto/organize
Expand Down
3 changes: 0 additions & 3 deletions tests/unit/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ def test_options(cli_runner, mocker):
"bla",
"--ca-bundle",
"yay",
"--no-render",
"--login-cert",
"puc",
"--login-cert-key",
Expand All @@ -47,7 +46,6 @@ def test_options(cli_runner, mocker):
assert set(kwargs) == {
"base_path",
"ca_bundle",
"render",
"login_cert",
"login_cert_key",
"password",
Expand All @@ -66,7 +64,6 @@ def test_options(cli_runner, mocker):
assert kwargs["url"] == "https://foo"
assert kwargs["username"] == "user"
assert kwargs["verify"] is True
assert kwargs["render"] is False


@pytest.fixture
Expand Down
136 changes: 2 additions & 134 deletions tests/unit/test_client_base.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import itertools

import pytest

from vault_cli import client, exceptions, testing
from vault_cli import client, exceptions


def test_get_client(mocker):
Expand Down Expand Up @@ -476,44 +474,6 @@ def test_vault_client_base_render_template_path_not_found(vault, template):
({"a": {"value": "b"}}, {"value": "b"}),
# Secret not a string
({"a": {"value": ["yay"]}}, {"value": ["yay"]}),
# Secret is a template without variable expansion
({"a": {"value": "!template!b"}, "b": {"value": "c"}}, {"value": "b"}),
# Secret is a template
(
{"a": {"value": "!template!{{ vault('b').value }}"}, "b": {"value": "c"}},
{"value": "c"},
),
# Secret is a dict with containing a template
(
{
"a": {"x": "!template!{{ vault('b').value }}", "y": "yay"},
"b": {"value": "c"},
},
{"x": "c", "y": "yay"},
),
# Finite recursion
(
{
"a": {"value": "!template!{{ vault('b').value }}"},
"b": {"value": "!template!{{ vault('c').value }}"},
"c": {"value": "d"},
},
{"value": "d"},
),
# Infinite Recursion
(
{
"a": {"value": "!template!{{ vault('b').value }}"},
"b": {"value": "!template!{{ vault('c').value }}"},
"c": {"value": "!template!{{ vault('a').value }}"},
},
{"value": '<recursive value "a">'},
),
# Direct Recursion
(
{"a": {"value": "!template!{{ vault('a').value }}"}},
{"value": '<recursive value "a">'},
),
],
)
def test_vault_client_base_get_secret(vault, vault_contents, expected):
Expand All @@ -522,23 +482,6 @@ def test_vault_client_base_get_secret(vault, vault_contents, expected):
assert vault.get_secret("a") == expected


def test_vault_client_base_get_secret_deprecation_warning(vault, caplog):
vault.db = {"a": {"value": "!template!b"}}
caplog.set_level("WARNING")

vault.get_secret("a")
assert "Templated values are deprecated" in caplog.records[0].message


def test_vault_client_base_get_secret_template_root(vault):
vault.base_path = "base"
vault.db = {"/base/a": {"value": '!template!{{ vault("a").value }} yay'}}

# In case of erroneous caching, e.g. a different cache entry
# for /base/a and base/a, we would find '<recursive value "a"> yay yay'
assert vault.get_secret("/base/a") == {"value": '<recursive value "a"> yay'}


def test_vault_client_base_get_secret_multiple_keys(vault):
vault.db = {"rabbitmq/creds/role": {"username": "foo", "password": "bar"}}
assert vault.get_secret("rabbitmq/creds/role") == {
Expand All @@ -547,22 +490,11 @@ def test_vault_client_base_get_secret_multiple_keys(vault):
}


def test_vault_client_base_get_secret_with_dict(vault):
vault.db = {
"credentials": {"value": {"username": "foo", "password": "bar"}},
"dsn": {
"value": "!template!proto://{{ vault('credentials')['value']['username'] }}:{{ vault('credentials').value.password }}@host"
},
}

assert vault.get_secret("dsn") == {"value": "proto://foo:bar@host"}


def test_vault_client_base_get_secret_not_found(vault):
vault.db = {}

with pytest.raises(exceptions.VaultSecretNotFound):
vault.get_secret("not-exiting")
vault.get_secret("not-existing")


def test_vault_client_base_get_secret_missing_key(vault):
Expand All @@ -572,20 +504,6 @@ def test_vault_client_base_get_secret_missing_key(vault):
vault.get_secret("a", key="username")


def test_vault_client_base_get_secret_template_error(vault, caplog):
vault.db = {"a": {"key": "!template!{{"}}

with pytest.raises(exceptions.VaultRenderTemplateError) as exc_info:
vault.get_secret("a")

assert str(exc_info.value) == 'Error while rendering secret at path "a"'
assert (
str(exc_info.value.__cause__)
== 'Error while rendering secret value for key "key"'
)
assert str(exc_info.value.__cause__.__cause__) == "Jinja2 template syntax error"


def test_vault_client_base_lookup_token(vault):
assert vault.lookup_token() == {"data": {"expire_time": "2100-01-01T00:00:00"}}

Expand Down Expand Up @@ -672,56 +590,6 @@ def test_vault_client_base_get_secret_implicit_cache(vault):
assert vault.get_secret("a") == {"value": "b"}


class RaceConditionTestVaultClient(testing.TestVaultClient):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.counter = itertools.count()

def _get_secret(self, path):
if path == "a":
val = next(self.counter)
return {"b": f"b{val}", "c": f"c{val}"}
return super()._get_secret(path)


def test_vault_client_base_get_secret_implicit_cache_no_race_condition():
# In this test we check that if a value is read several times by
# a template, implicit caching makes sure we have the same value
# every time.

# Values returned by this client keep changing

vault = RaceConditionTestVaultClient()

with vault:
assert vault.get_secret("a") == {"b": "b0", "c": "c0"}
with vault:
assert vault.get_secret("a") == {"b": "b1", "c": "c1"}

vault.db = {"d": {"value": """!template!{{ vault("a").b }}-{{ vault("a").c }}"""}}

# b2-c3 would be the value if caching didn't work.
with vault:
assert vault.get_secret("d") == {"value": "b2-c2"}


def test_vault_client_base_get_secrets_implicit_cache_no_race_condition():
# In this test, the same value is read twice by get-all and template
# We check that 2 values are consistent

vault = RaceConditionTestVaultClient()

vault.db = {
"a": {},
"d": {"value": """!template!{{ vault("a").b }}-{{ vault("a").c }}"""},
}

assert vault.get_secrets("") == {
"a": {"b": "b0", "c": "c0"},
"d": {"value": "b0-c0"},
}


def test_vault_client_base_get_secret_explicit_cache(vault):
vault.db = {"a": {"value": "b"}}
with vault:
Expand Down
5 changes: 3 additions & 2 deletions vault_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ def repr_octal(value: Optional[int]) -> Optional[str]:
)
@click.option(
"--render/--no-render",
default=settings.DEFAULTS.render,
help="Render templated values",
default=False,
help="Deprecated / unused",
)
@click.option(
"--umask",
Expand Down Expand Up @@ -174,6 +174,7 @@ def cli(ctx: click.Context, verbose: int, umask: int, **kwargs) -> None:
(including VAULT_CLI_PASSWORD and VAULT_CLI_TOKEN).
"""
kwargs.pop("render")
kwargs.pop("config_file")
set_verbosity(verbose)
set_umask(umask)
Expand Down
Loading

0 comments on commit 3ba3955

Please sign in to comment.