From c47dbaa34350dff7940a468cb7242eed2f4fc130 Mon Sep 17 00:00:00 2001 From: Wiktor Latanowicz Date: Mon, 22 Sep 2025 21:13:32 +0200 Subject: [PATCH 1/5] Add option to filter dumped secrets --- README.md | 7 +++++++ ecsctrl/cli.py | 4 +++- ecsctrl/dump/secrets.py | 7 ++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 701f6b5..8e9084f 100644 --- a/README.md +++ b/README.md @@ -192,3 +192,10 @@ Secrets are represented in yaml as SSM name and value pairs. They're uploaded to ```bash ecsctrl secrets store -e production.env secrets.yaml ``` + +Dump secrets from SSM parameter store. You can optionally filter params by name using regexp. +--- + +```bash +ecsctrl secrets dump -e production.env --filter "db_.*" secrets.yaml +``` diff --git a/ecsctrl/cli.py b/ecsctrl/cli.py index a887f6d..c762cf0 100644 --- a/ecsctrl/cli.py +++ b/ecsctrl/cli.py @@ -309,11 +309,13 @@ def store( @secrets.command() @click.argument("spec-file", type=str) +@click.option("--filter", type=str, default=None, help="Export only secrets matching given regexp pattern") @common_options @click.pass_context def dump( ctx, spec_file, + filter, env_file, json_file, var, @@ -323,7 +325,7 @@ def dump( vars = VarsLoader(env_file, var, json_file, sys_env).load() var_lut = generate_var_lut(vars) ssm = BotoClient("ssm", dry_run=ctx.obj["boto_client"].dry_run) - secrets = dump_secrets(ssm) + secrets = dump_secrets(ssm, filter) render_dumped_secrets(click, secrets, var_lut, spec_file) diff --git a/ecsctrl/dump/secrets.py b/ecsctrl/dump/secrets.py index f5e1561..43097c4 100644 --- a/ecsctrl/dump/secrets.py +++ b/ecsctrl/dump/secrets.py @@ -1,6 +1,6 @@ +import re from . import substitute_with_expressions - def list_secrets(ssm): should_fetch = True next_token = None @@ -17,7 +17,7 @@ def list_secrets(ssm): yield parameter -def dump_secrets(ssm): +def dump_secrets(ssm, filter=None): for parameter in list_secrets(ssm): parameter_name = parameter["Name"] response = ssm.call( @@ -26,7 +26,8 @@ def dump_secrets(ssm): WithDecryption=True, ) - yield parameter_name, response["Parameter"]["Value"] + if filter is None or re.match(filter, parameter_name): + yield parameter_name, response["Parameter"]["Value"] def render_dumped_secrets(click, secrets, vars_lut, target_file): From e052680b6bb06d85d8ceb376451a38b5e14b32e0 Mon Sep 17 00:00:00 2001 From: Wiktor Latanowicz Date: Mon, 22 Sep 2025 21:15:12 +0200 Subject: [PATCH 2/5] Add gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c182e37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +env +*.egg-info From f8306795a02d6d0e2a70e4e7bd68c44831414003 Mon Sep 17 00:00:00 2001 From: Wiktor Latanowicz Date: Mon, 22 Sep 2025 21:15:18 +0200 Subject: [PATCH 3/5] Fix GHA --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 81df390..fc2588c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: python-version: ${{ matrix.python }} - name: Cache python packages - uses: actions/cache@v2 + uses: actions/cache@v4 env: cache-name: test-python-packages with: From 04f41cf14b11b4677b86ab7094cf642291509b52 Mon Sep 17 00:00:00 2001 From: Wiktor Latanowicz Date: Mon, 22 Sep 2025 21:16:12 +0200 Subject: [PATCH 4/5] Fix GHA - python versions --- .github/workflows/tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fc2588c..dabe46b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,10 +11,12 @@ jobs: strategy: matrix: python: - - "3.7" - "3.8" - "3.9" - "3.10" + - "3.11" + - "3.12" + - "3.13" steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python }} From 2cf31c0abaca8b4c448b67dc9adb0b7ab3028fd0 Mon Sep 17 00:00:00 2001 From: Wiktor Latanowicz Date: Mon, 22 Sep 2025 21:18:20 +0200 Subject: [PATCH 5/5] Format files --- ecsctrl/cli.py | 7 ++++++- ecsctrl/dump/secrets.py | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ecsctrl/cli.py b/ecsctrl/cli.py index c762cf0..f12634e 100644 --- a/ecsctrl/cli.py +++ b/ecsctrl/cli.py @@ -309,7 +309,12 @@ def store( @secrets.command() @click.argument("spec-file", type=str) -@click.option("--filter", type=str, default=None, help="Export only secrets matching given regexp pattern") +@click.option( + "--filter", + type=str, + default=None, + help="Export only secrets matching given regexp pattern", +) @common_options @click.pass_context def dump( diff --git a/ecsctrl/dump/secrets.py b/ecsctrl/dump/secrets.py index 43097c4..6a21239 100644 --- a/ecsctrl/dump/secrets.py +++ b/ecsctrl/dump/secrets.py @@ -1,6 +1,7 @@ import re from . import substitute_with_expressions + def list_secrets(ssm): should_fetch = True next_token = None