From 4abed82b8afa55152180987455e3e756723adb16 Mon Sep 17 00:00:00 2001 From: Stefan Reimer Date: Tue, 12 Apr 2022 13:16:42 +0200 Subject: [PATCH] feat: Prevent blacklisted outputs from being written to output files, add easy stack reset for Pulumi stacks --- cloudbender/cli.py | 6 +++--- cloudbender/stack.py | 26 +++++++++++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/cloudbender/cli.py b/cloudbender/cli.py index 0156b5b..a34df52 100644 --- a/cloudbender/cli.py +++ b/cloudbender/cli.py @@ -153,18 +153,18 @@ def refresh(cb, stack_name): @click.command() @click.argument("stack_name") @click.option( - "--reset", + "-r", "--remove-pending-operations", is_flag=True, help="All pending stack operations are removed and the stack will be re-imported", ) @click.pass_obj -def export(cb, stack_name, reset=False): +def export(cb, stack_name, remove_pending_operations=False): """Exports a Pulumi stack to repair state""" stacks = _find_stacks(cb, [stack_name]) for s in stacks: if s.mode == "pulumi": - s.export(reset) + s.export(remove_pending_operations) else: logger.info("{} uses Cloudformation, export skipped.".format(s.stackname)) diff --git a/cloudbender/stack.py b/cloudbender/stack.py index fe4d365..06ed35b 100644 --- a/cloudbender/stack.py +++ b/cloudbender/stack.py @@ -526,6 +526,16 @@ class Stack(object): ) ensure_dir(os.path.join(self.ctx["outputs_path"], self.rel_path)) + # Blacklist at least AWS SecretKeys from leaking into git + # Pulumi to the rescue soon + blacklist = [".*SecretAccessKey.*"] + sanitized_outputs = {} + for k in self.outputs.keys(): + sanitized_outputs[k] = self.outputs[k] + for val in blacklist: + if re.match(val, k, re.IGNORECASE): + sanitized_outputs[k] = "" + jenv = JinjaEnv() template = jenv.from_string(my_template) data = { @@ -533,7 +543,7 @@ class Stack(object): "timestamp": datetime.strftime( datetime.now(tzutc()), "%d/%m/%y %H:%M" ), - "outputs": self.outputs, + "outputs": sanitized_outputs, "parameters": self.parameters, } @@ -840,7 +850,7 @@ class Stack(object): def preview(self): """Preview a Pulumi stack up operation""" - pulumi_init(self).preview(on_output=self._log_pulumi) + pulumi_init(self, create=True).preview(on_output=self._log_pulumi) return @@ -852,19 +862,25 @@ class Stack(object): # now lets import each defined resource for r in self._pulumi_code.RESOURCES: - args = ["import", r["type"], r["name"], r["id"], "--yes"] + r_id = r["id"] + if not r_id: + r_id = input("Please enter ID for {} ({}):".format(r["name"], r["type"])) + + logger.info("Importing {} ({}) as {}".format(r_id, r["type"], r["name"])) + + args = ["import", r["type"], r["name"], r_id, "--yes"] pulumi_stack._run_pulumi_cmd_sync(args) return @pulumi_ws - def export(self, reset): + def export(self, remove_pending_operations): """Exports a Pulumi stack""" pulumi_stack = pulumi_init(self) deployment = pulumi_stack.export_stack() - if reset: + if remove_pending_operations: deployment.deployment.pop("pending_operations", None) pulumi_stack.import_stack(deployment) logger.info("Removed all pending_operations from %s" % self.stackname)