<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://pascal-nehlsen.de/blog</id>
    <title>Pascal Nehlsen — Writing</title>
    <updated>2026-04-28T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://pascal-nehlsen.de/blog"/>
    <subtitle>Build notes on platform and security engineering.</subtitle>
    <icon>https://pascal-nehlsen.de/img/favicon.svg</icon>
    <rights>© 2026 Pascal Nehlsen</rights>
    <entry>
        <title type="html"><![CDATA[Ephemeral AWS Sandboxes: 80+ Isolated Environments at Half the Cost]]></title>
        <id>https://pascal-nehlsen.de/blog/ephemeral-aws-sandboxes-cost</id>
        <link href="https://pascal-nehlsen.de/blog/ephemeral-aws-sandboxes-cost"/>
        <updated>2026-04-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Per-user n8n sandboxes on AWS burstable EC2, sized for the median rather than the peak, with lifecycle automation that reclaims idle instances — 80+ real environments at half the compute cost.]]></summary>
        <content type="html"><![CDATA[<p>Giving every learner a shared environment is cheap and miserable — one person breaks it and
everyone is blocked. Giving everyone a fixed, always-on instance is clean and expensive. This
post is about a third option: per-user, production-like sandboxes on AWS that spin up on demand,
clean themselves up, and cost about half what fixed-size instances would.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-isolation-matters-more-than-it-looks">Why isolation matters more than it looks<a href="https://pascal-nehlsen.de/blog/ephemeral-aws-sandboxes-cost#why-isolation-matters-more-than-it-looks" class="hash-link" aria-label="Direct link to Why isolation matters more than it looks" title="Direct link to Why isolation matters more than it looks" translate="no">​</a></h2>
<p>For hands-on automation work (in this case, n8n sandboxes for trainees), shared state is
poison. A misconfigured workflow, a runaway loop, a deleted credential — in a shared box, that's
everyone's problem. Isolation means one person's mistake is a learning moment, not an outage for
the cohort.</p>
<p>The requirement, then: <strong>80+ independent, production-like environments</strong>, each disposable.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="burstable-instances-fit-the-usage-shape">Burstable instances fit the usage shape<a href="https://pascal-nehlsen.de/blog/ephemeral-aws-sandboxes-cost#burstable-instances-fit-the-usage-shape" class="hash-link" aria-label="Direct link to Burstable instances fit the usage shape" title="Direct link to Burstable instances fit the usage shape" translate="no">​</a></h2>
<p>The usage pattern is bursty: intense activity during a session, near-idle the rest of the time.
That's exactly what AWS burstable instances (<code>t3</code> / <code>t4g</code>) are built for — you pay for a baseline
and accrue CPU credits while idle, spending them during bursts.</p>
<p>Two choices did most of the cost work:</p>
<ul>
<li class=""><strong><code>t4g</code> (Graviton/ARM)</strong> where the workload is architecture-agnostic — better price/performance.</li>
<li class=""><strong>Right-sizing to the burst</strong>, not the peak-of-peaks, because credits absorb short spikes.</li>
</ul>
<p>Against fixed-size, always-on instances sized for peak, this kept compute costs roughly <strong>50%
lower</strong>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="lifecycle-automation-is-the-whole-game">Lifecycle automation is the whole game<a href="https://pascal-nehlsen.de/blog/ephemeral-aws-sandboxes-cost#lifecycle-automation-is-the-whole-game" class="hash-link" aria-label="Direct link to Lifecycle automation is the whole game" title="Direct link to Lifecycle automation is the whole game" translate="no">​</a></h2>
<p>Ephemeral only saves money if the environments actually go away. The lifecycle is automated
end-to-end:</p>
<ol>
<li class=""><strong>Provision</strong> on demand from a Terraform-defined template — instance, security group,
bootstrapped n8n, tagged with <code>owner</code> and <code>expires-at</code>.</li>
<li class=""><strong>Run</strong> for the session; isolated networking per sandbox.</li>
<li class=""><strong>Reap</strong> automatically — a scheduled job terminates instances past their <code>expires-at</code>, so a
forgotten sandbox can't quietly bill for a week.</li>
</ol>
<div class="language-hcl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-hcl codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token property" style="color:rgb(128, 203, 196)">tags</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token property" style="color:rgb(128, 203, 196)">owner</span><span class="token plain">       </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> var.trainee_id</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token property" style="color:rgb(128, 203, 196)">purpose</span><span class="token plain">     </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"n8n-sandbox"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token property" style="color:rgb(128, 203, 196)">expires-at</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> var.session_end   </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># consumed by the reaper</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>The <code>expires-at</code> tag is the linchpin: it turns "please remember to shut it down" into a
guaranteed, automated teardown.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="guardrails-so-a-sandbox-stays-a-sandbox">Guardrails so a sandbox stays a sandbox<a href="https://pascal-nehlsen.de/blog/ephemeral-aws-sandboxes-cost#guardrails-so-a-sandbox-stays-a-sandbox" class="hash-link" aria-label="Direct link to Guardrails so a sandbox stays a sandbox" title="Direct link to Guardrails so a sandbox stays a sandbox" translate="no">​</a></h2>
<p>Isolation and cost control need the same enforcement discipline as any other environment:</p>
<ul>
<li class=""><strong>Scoped IAM</strong> per sandbox — no shared, over-privileged role.</li>
<li class=""><strong>Egress limits</strong> so a sandbox can't become a crypto-mining surprise.</li>
<li class=""><strong>Hard expiry</strong> so cost is bounded by design, not by vigilance.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-result">The result<a href="https://pascal-nehlsen.de/blog/ephemeral-aws-sandboxes-cost#the-result" class="hash-link" aria-label="Direct link to The result" title="Direct link to The result" translate="no">​</a></h2>
<p>The outcome was <strong>80+ trainees, each with an isolated, production-like environment</strong>, provisioned
on demand and reaped automatically — at roughly <strong>half the compute cost</strong> of fixed-size
instances. Isolation stopped being a luxury and became the cheap default.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="takeaways">Takeaways<a href="https://pascal-nehlsen.de/blog/ephemeral-aws-sandboxes-cost#takeaways" class="hash-link" aria-label="Direct link to Takeaways" title="Direct link to Takeaways" translate="no">​</a></h2>
<ul>
<li class="">Match instance type to the <strong>usage shape</strong>; bursty work loves burstable instances.</li>
<li class="">Consider <strong>Graviton (<code>t4g</code>)</strong> for architecture-agnostic workloads.</li>
<li class="">Make teardown <strong>automated and tag-driven</strong> — ephemeral that never expires is just expensive.</li>
<li class="">Bound cost <strong>by design</strong> (hard expiry) instead of relying on people to remember.</li>
</ul>]]></content>
        <author>
            <name>Pascal Nehlsen</name>
            <email>mail@pascal-nehlsen.de</email>
            <uri>https://github.com/PascalNehlsen</uri>
        </author>
        <category label="AWS" term="AWS"/>
        <category label="Cost" term="Cost"/>
        <category label="Terraform" term="Terraform"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[SLO-Driven Automated Rollback: Let the Metrics Pull the Cord]]></title>
        <id>https://pascal-nehlsen.de/blog/slo-driven-automated-rollback</id>
        <link href="https://pascal-nehlsen.de/blog/slo-driven-automated-rollback"/>
        <updated>2026-03-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Wiring Prometheus, Grafana and structured logging into a deployment pipeline so an SLO breach triggers rollback automatically — and why a rollback without an SLO behind it is a button nobody trusts.]]></summary>
        <content type="html"><![CDATA[<p>A deploy that breaks production at 02:00 shouldn't wait for a human to wake up, read a dashboard,
and decide to roll back. If you can <em>define</em> what "broken" means in terms your monitoring can
measure, you can let the pipeline pull the cord itself. This post walks through wiring
observability into deployment so that an SLO breach triggers an automatic rollback.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="start-with-an-slo-you-can-actually-measure">Start with an SLO you can actually measure<a href="https://pascal-nehlsen.de/blog/slo-driven-automated-rollback#start-with-an-slo-you-can-actually-measure" class="hash-link" aria-label="Direct link to Start with an SLO you can actually measure" title="Direct link to Start with an SLO you can actually measure" translate="no">​</a></h2>
<p>An automated rollback is only as trustworthy as the signal that fires it. Vague goals ("the app
should be fast") don't work. Concrete, measurable SLOs do:</p>
<ul>
<li class=""><strong>Availability</strong>: <code>&gt;= 99.9%</code> of requests return non-5xx over a 5-minute window.</li>
<li class=""><strong>Latency</strong>: <code>p95 &lt; 300ms</code> over a 5-minute window.</li>
<li class=""><strong>Error budget</strong>: a burn-rate threshold that distinguishes a blip from a regression.</li>
</ul>
<p>These become PromQL expressions, not slideware:</p>
<div class="language-promql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-promql codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token plain"># 5xx rate over the last 5 minutes, per service</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">sum(rate(http_requests_total{status=~"5..", service="appointments-api"}[5m]))</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">sum(rate(http_requests_total{service="appointments-api"}[5m]))</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-observability-spine">The observability spine<a href="https://pascal-nehlsen.de/blog/slo-driven-automated-rollback#the-observability-spine" class="hash-link" aria-label="Direct link to The observability spine" title="Direct link to The observability spine" translate="no">​</a></h2>
<p>Three signals feed the decision:</p>
<ul>
<li class=""><strong>Prometheus</strong> scrapes request rate, error rate, and latency histograms.</li>
<li class=""><strong>Grafana</strong> visualises them and hosts the alerting rules humans reason about.</li>
<li class=""><strong>Structured logging</strong> (JSON, with a <code>trace_id</code>) makes the <em>why</em> diggable once the <em>what</em> fires.</li>
</ul>
<p>The key discipline: the same query that draws the dashboard line is the one that gates the deploy.
No separate, drifting "rollback logic".</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-rollback-gate">The rollback gate<a href="https://pascal-nehlsen.de/blog/slo-driven-automated-rollback#the-rollback-gate" class="hash-link" aria-label="Direct link to The rollback gate" title="Direct link to The rollback gate" translate="no">​</a></h2>
<p>After a deploy promotes a new revision, the pipeline enters a <strong>bake window</strong> — say five minutes
— during which it watches the SLO queries:</p>
<ol>
<li class="">Promote new revision, shift traffic.</li>
<li class="">Poll the SLO expressions across the bake window.</li>
<li class="">If any SLO breaches its threshold (with a burn-rate guard to avoid flapping), <strong>trigger
rollback</strong> to the last-good revision.</li>
<li class="">Emit a structured event: revision, breached SLO, observed value, timestamp.</li>
</ol>
<p>Because rollback is just "route traffic back to the previous known-good revision", it's fast and
boring — exactly what you want at 02:00.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="guard-against-false-alarms">Guard against false alarms<a href="https://pascal-nehlsen.de/blog/slo-driven-automated-rollback#guard-against-false-alarms" class="hash-link" aria-label="Direct link to Guard against false alarms" title="Direct link to Guard against false alarms" translate="no">​</a></h2>
<p>Automation that rolls back on noise is worse than no automation — it erodes trust. Two guards:</p>
<ul>
<li class=""><strong>Burn-rate, not instantaneous value</strong>: a single spike shouldn't trigger; sustained burn should.</li>
<li class=""><strong>Minimum traffic threshold</strong>: don't compute an error <em>rate</em> on three requests.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-result">The result<a href="https://pascal-nehlsen.de/blog/slo-driven-automated-rollback#the-result" class="hash-link" aria-label="Direct link to The result" title="Direct link to The result" translate="no">​</a></h2>
<p>With SLOs defined as measurable queries and a bake-window rollback gate, the deployment error
rate stayed <strong>under 2%</strong> — and the mean time to detect critical failures dropped to <strong>under five
minutes</strong>, because detection and remediation were the same automated step.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="takeaways">Takeaways<a href="https://pascal-nehlsen.de/blog/slo-driven-automated-rollback#takeaways" class="hash-link" aria-label="Direct link to Takeaways" title="Direct link to Takeaways" translate="no">​</a></h2>
<ul>
<li class="">Define SLOs as <strong>queries your monitoring already evaluates</strong>, not prose.</li>
<li class="">Reuse the <strong>same expression</strong> for the dashboard and the rollback gate.</li>
<li class="">Add a <strong>bake window</strong> and <strong>burn-rate guards</strong> so you roll back on regressions, not noise.</li>
<li class="">A good rollback is <strong>fast and boring</strong>: route traffic to the last-good revision.</li>
</ul>]]></content>
        <author>
            <name>Pascal Nehlsen</name>
            <email>mail@pascal-nehlsen.de</email>
            <uri>https://github.com/PascalNehlsen</uri>
        </author>
        <category label="Observability" term="Observability"/>
        <category label="CI/CD" term="CI/CD"/>
        <category label="DevSecOps" term="DevSecOps"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Agentic DevOps Runbooks with a Human-Approval Layer]]></title>
        <id>https://pascal-nehlsen.de/blog/agentic-runbooks-mcp-human-approval</id>
        <link href="https://pascal-nehlsen.de/blog/agentic-runbooks-mcp-human-approval"/>
        <updated>2026-02-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[An MCP server that gathers incident context and proposes a remediation, then stops. Every state-changing action needs human approval, is logged with its reasoning, and is reversible.]]></summary>
        <content type="html"><![CDATA[<p>"Let the AI fix it" is a great way to turn a small incident into a large one. But most of the
<em>toil</em> in incident response isn't the fix — it's the gathering: pulling logs, checking
deploy history, correlating metrics, reconstructing what changed. That part is safe to automate.
This post describes a runbook executor that automates the gathering and the <em>proposing</em>, while
keeping a human firmly in front of anything destructive.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-design-principle-propose-dont-perform">The design principle: propose, don't perform<a href="https://pascal-nehlsen.de/blog/agentic-runbooks-mcp-human-approval#the-design-principle-propose-dont-perform" class="hash-link" aria-label="Direct link to The design principle: propose, don't perform" title="Direct link to The design principle: propose, don't perform" translate="no">​</a></h2>
<p>The system splits every runbook step into two categories:</p>
<ul>
<li class=""><strong>Read actions</strong> — fetch logs, read Terraform state, list recent deployments, query metrics.
These run automatically.</li>
<li class=""><strong>Write actions</strong> — restart a service, roll back a release, scale a resource, change an IAM
binding. These are <em>proposed</em> and require explicit approval before they execute.</li>
</ul>
<p>The LLM lives in the read half and at the proposal boundary. It never holds the keys to a write.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mcp-as-the-integration-surface">MCP as the integration surface<a href="https://pascal-nehlsen.de/blog/agentic-runbooks-mcp-human-approval#mcp-as-the-integration-surface" class="hash-link" aria-label="Direct link to MCP as the integration surface" title="Direct link to MCP as the integration surface" translate="no">​</a></h2>
<p>The executor is an <a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">MCP</a> server, written in Go, exposing a
small set of tools to the agent:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token plain">get_recent_deployments(service)      # read</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">get_logs(service, since, severity)   # read</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">get_terraform_state(module)          # read</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">propose_rollback(service, revision)  # write → queued for approval</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">propose_restart(service)             # write → queued for approval</span><br></div></code></pre></div></div>
<p>Read tools return context. Write tools don't act — they enqueue a <strong>proposal</strong> with a
human-readable diff of what <em>would</em> happen, and return a ticket ID. Nothing changes in the world
until a human approves that ticket.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="every-critical-action-is-auditable-and-reversible">Every critical action is auditable and reversible<a href="https://pascal-nehlsen.de/blog/agentic-runbooks-mcp-human-approval#every-critical-action-is-auditable-and-reversible" class="hash-link" aria-label="Direct link to Every critical action is auditable and reversible" title="Direct link to Every critical action is auditable and reversible" translate="no">​</a></h2>
<p>Three properties are non-negotiable for a write action:</p>
<ol>
<li class=""><strong>Auditable</strong> — who proposed it (which runbook, which agent run), who approved it, when, and
the exact parameters. This is written to a durable log before execution.</li>
<li class=""><strong>Reversible</strong> — a rollback has a forward and a backward direction; the executor records
enough state to undo it.</li>
<li class=""><strong>Explicitly approved</strong> — approval is a deliberate action by a named human, not a default or
a timeout.</li>
</ol>
<p>The approval step is where automation and accountability meet. The agent can be wrong; the
guardrail assumes it will be.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-it-actually-buys-you">What it actually buys you<a href="https://pascal-nehlsen.de/blog/agentic-runbooks-mcp-human-approval#what-it-actually-buys-you" class="hash-link" aria-label="Direct link to What it actually buys you" title="Direct link to What it actually buys you" translate="no">​</a></h2>
<p>For known failure classes — a bad deploy, a wedged worker, a config regression — the executor
collapses the slow part of the response. Instead of ten minutes of context-gathering under
pressure, the on-call engineer opens a proposal that already contains the logs, the diff, the
suspected cause, and a pre-filled remediation waiting for a yes/no.</p>
<p>In practice this cut response time for known failure classes by around <strong>60%</strong> — not by acting
faster than a human, but by removing the gathering a human would have done anyway.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="takeaways">Takeaways<a href="https://pascal-nehlsen.de/blog/agentic-runbooks-mcp-human-approval#takeaways" class="hash-link" aria-label="Direct link to Takeaways" title="Direct link to Takeaways" translate="no">​</a></h2>
<ul>
<li class="">Automate the <strong>gathering and the proposal</strong>; gate the <strong>action</strong> behind a human.</li>
<li class="">Model write operations as <strong>reversible proposals with a diff</strong>, never fire-and-forget calls.</li>
<li class="">Make <strong>auditability a precondition</strong> of execution, not an afterthought.</li>
<li class="">The goal isn't autonomy — it's a faster, calmer human decision.</li>
</ul>]]></content>
        <author>
            <name>Pascal Nehlsen</name>
            <email>mail@pascal-nehlsen.de</email>
            <uri>https://github.com/PascalNehlsen</uri>
        </author>
        <category label="Agents & MCP" term="Agents & MCP"/>
        <category label="DevSecOps" term="DevSecOps"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Golden Paths on GCP: Cutting Provisioning Time by 80% with Terraform]]></title>
        <id>https://pascal-nehlsen.de/blog/terraform-golden-paths-gcp</id>
        <link href="https://pascal-nehlsen.de/blog/terraform-golden-paths-gcp"/>
        <updated>2026-01-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How modularising a Google Cloud environment around team intent rather than the resource catalogue turned a four-hour manual setup into a sub-45-minute self-service path.]]></summary>
        <content type="html"><![CDATA[<p>The fastest way to slow a team down is to make them wait on infrastructure. When every new
service means a four-hour manual walk through the GCP console, engineers batch their requests,
context-switch while they wait, and quietly build snowflakes. This post is about replacing that
ritual with a golden path — a paved, opinionated route that provisions a production-like
environment in under 45 minutes, self-service.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-problem-with-just-click-it-in-the-console">The problem with "just click it in the console"<a href="https://pascal-nehlsen.de/blog/terraform-golden-paths-gcp#the-problem-with-just-click-it-in-the-console" class="hash-link" aria-label="Direct link to The problem with &quot;just click it in the console&quot;" title="Direct link to The problem with &quot;just click it in the console&quot;" translate="no">​</a></h2>
<p>Manual provisioning fails in three predictable ways:</p>
<ul>
<li class=""><strong>It's slow.</strong> Four hours per environment, most of it waiting and clicking.</li>
<li class=""><strong>It drifts.</strong> No two environments end up identical, so "works in staging" stops meaning anything.</li>
<li class=""><strong>It's opaque.</strong> There's no review, no history, no way to answer "who changed this IAM binding and why".</li>
</ul>
<p>Infrastructure as Code fixes all three at once — but only if the modules are shaped so that
using them correctly is the path of least resistance.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="modularise-around-intent-not-resources">Modularise around intent, not resources<a href="https://pascal-nehlsen.de/blog/terraform-golden-paths-gcp#modularise-around-intent-not-resources" class="hash-link" aria-label="Direct link to Modularise around intent, not resources" title="Direct link to Modularise around intent, not resources" translate="no">​</a></h2>
<p>The mistake I see most often is a Terraform layout that mirrors the GCP API: one module per
resource type. That optimises for the platform team and punishes everyone else.</p>
<p>Instead, modularise around what teams actually ask for:</p>
<div class="language-hcl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-hcl codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">module</span><span class="token keyword type variable" style="color:rgb(214, 222, 235)"> "service" </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token property" style="color:rgb(128, 203, 196)">source</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"./modules/cloud-run-service"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token property" style="color:rgb(128, 203, 196)">name</span><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"appointments-api"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token property" style="color:rgb(128, 203, 196)">team</span><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"scheduling"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token property" style="color:rgb(128, 203, 196)">image</span><span class="token plain">   </span><span class="token punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token plain"> var.image</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># sensible, secure defaults baked in:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># - private IP Cloud SQL connection</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># - least-privilege service account</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># - structured logging + trace export</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>A single <code>module "service"</code> block stands up Cloud Run, wires a least-privilege service account,
connects Cloud SQL over a private IP, and exports logs and traces. The consumer specifies
<em>intent</em> — a service for a team — not thirty individual resources.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="guardrails-belong-in-the-module">Guardrails belong in the module<a href="https://pascal-nehlsen.de/blog/terraform-golden-paths-gcp#guardrails-belong-in-the-module" class="hash-link" aria-label="Direct link to Guardrails belong in the module" title="Direct link to Guardrails belong in the module" translate="no">​</a></h2>
<p>A golden path is only golden if the safe choice is the default choice:</p>
<ul>
<li class=""><strong>IAM</strong>: modules mint scoped service accounts; nobody hand-edits project-level bindings.</li>
<li class=""><strong>Networking</strong>: private IP by default, public egress opt-in and reviewed.</li>
<li class=""><strong>Tagging/labels</strong>: <code>team</code>, <code>cost-center</code>, and <code>environment</code> are required variables — no label, no plan.</li>
</ul>
<p>Because these are enforced in code, a misconfiguration is a failed <code>terraform plan</code>, not a
production incident discovered three weeks later.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="delivery-via-gitops">Delivery via GitOps<a href="https://pascal-nehlsen.de/blog/terraform-golden-paths-gcp#delivery-via-gitops" class="hash-link" aria-label="Direct link to Delivery via GitOps" title="Direct link to Delivery via GitOps" translate="no">​</a></h2>
<p>The modules are only half the story; delivery is the other half. Every change flows through a
pull request:</p>
<ol>
<li class=""><code>terraform plan</code> runs in CI and posts the diff on the PR.</li>
<li class="">A reviewer approves the <em>plan</em>, not a vague description of it.</li>
<li class="">Merge to <code>main</code> triggers <code>terraform apply</code> through GitHub Actions (or Argo CD for the
Kubernetes-shaped pieces).</li>
</ol>
<p>The audit trail is the git history. "Who changed this and why" is answered by <code>git blame</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-result">The result<a href="https://pascal-nehlsen.de/blog/terraform-golden-paths-gcp#the-result" class="hash-link" aria-label="Direct link to The result" title="Direct link to The result" translate="no">​</a></h2>
<p>Consolidating the environment into intent-shaped modules with guardrails and GitOps delivery
took provisioning from <strong>~4 hours of manual work to under 45 minutes</strong>, fully automated — an
80% reduction. Just as importantly, infrastructure support tickets dropped sharply, because the
common requests became self-service.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="takeaways">Takeaways<a href="https://pascal-nehlsen.de/blog/terraform-golden-paths-gcp#takeaways" class="hash-link" aria-label="Direct link to Takeaways" title="Direct link to Takeaways" translate="no">​</a></h2>
<ul>
<li class="">Shape modules around <strong>team intent</strong>, not the cloud provider's resource catalogue.</li>
<li class="">Bake security defaults <strong>into</strong> the module so the safe path is the easy path.</li>
<li class="">Deliver through <strong>pull requests</strong> so the plan is reviewed and the history is the audit log.</li>
<li class="">Measure the thing that matters: <strong>time-to-environment</strong>, not lines of HCL.</li>
</ul>]]></content>
        <author>
            <name>Pascal Nehlsen</name>
            <email>mail@pascal-nehlsen.de</email>
            <uri>https://github.com/PascalNehlsen</uri>
        </author>
        <category label="Terraform" term="Terraform"/>
        <category label="GCP" term="GCP"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
        <category label="CI/CD" term="CI/CD"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Git Security - Protecting Your Source Code and Commits]]></title>
        <id>https://pascal-nehlsen.de/blog/git-security-practices</id>
        <link href="https://pascal-nehlsen.de/blog/git-security-practices"/>
        <updated>2024-05-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Signed commits, secret scanning before a push, protected branches, and what to actually do when a key does make it into history.]]></summary>
        <content type="html"><![CDATA[<p>Your Git repository is more than code—it's credentials, API keys, intellectual property, and your company's crown jewels. Let's secure it properly.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-github-token-incident">The GitHub Token Incident<a href="https://pascal-nehlsen.de/blog/git-security-practices#the-github-token-incident" class="hash-link" aria-label="Direct link to The GitHub Token Incident" title="Direct link to The GitHub Token Incident" translate="no">​</a></h2>
<p>Last week, an intern pushed a commit containing a GitHub Personal Access Token with full repo access. Within <strong>minutes</strong>, an automated bot found it and:</p>
<ol>
<li class="">Cloned all our private repositories</li>
<li class="">Scraped secrets from commit history</li>
<li class="">Created backdoor accounts</li>
</ol>
<p>This post is about preventing that.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-commit-signing-with-gpg">1. Commit Signing with GPG<a href="https://pascal-nehlsen.de/blog/git-security-practices#1-commit-signing-with-gpg" class="hash-link" aria-label="Direct link to 1. Commit Signing with GPG" title="Direct link to 1. Commit Signing with GPG" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-sign-commits">Why Sign Commits?<a href="https://pascal-nehlsen.de/blog/git-security-practices#why-sign-commits" class="hash-link" aria-label="Direct link to Why Sign Commits?" title="Direct link to Why Sign Commits?" translate="no">​</a></h3>
<p>Anyone can impersonate you with <code>git config user.name "Your Name"</code>. Signed commits prove authenticity.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="setup-gpg-key">Setup GPG Key<a href="https://pascal-nehlsen.de/blog/git-security-practices#setup-gpg-key" class="hash-link" aria-label="Direct link to Setup GPG Key" title="Direct link to Setup GPG Key" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Generate GPG key</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">gpg --full-generate-key</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Choose: RSA and RSA, 4096 bits, no expiration</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># List keys</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">gpg --list-secret-keys --keyid-format</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">long</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Export public key</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">gpg </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--armor</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--export</span><span class="token plain"> YOUR_KEY_ID</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Add to GitHub: Settings &gt; SSH and GPG keys &gt; New GPG key</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-git">Configure Git<a href="https://pascal-nehlsen.de/blog/git-security-practices#configure-git" class="hash-link" aria-label="Direct link to Configure Git" title="Direct link to Configure Git" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Set signing key</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> user.signingkey YOUR_KEY_ID</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Sign all commits by default</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> commit.gpgsign </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Sign tags</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> tag.gpgSign </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="verify-signed-commits">Verify Signed Commits<a href="https://pascal-nehlsen.de/blog/git-security-practices#verify-signed-commits" class="hash-link" aria-label="Direct link to Verify Signed Commits" title="Direct link to Verify Signed Commits" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Verify last commit</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> verify-commit HEAD</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Show signature</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> log --show-signature</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Verify tag</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> verify-tag v1.0.0</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-branch-protection-rules">2. Branch Protection Rules<a href="https://pascal-nehlsen.de/blog/git-security-practices#2-branch-protection-rules" class="hash-link" aria-label="Direct link to 2. Branch Protection Rules" title="Direct link to 2. Branch Protection Rules" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="github-branch-protection">GitHub Branch Protection<a href="https://pascal-nehlsen.de/blog/git-security-practices#github-branch-protection" class="hash-link" aria-label="Direct link to GitHub Branch Protection" title="Direct link to GitHub Branch Protection" translate="no">​</a></h3>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># .github/branch-protection.yml</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule">protection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">required_status_checks</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">strict</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">contexts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"security/sast"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"security/secrets-scan"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"tests/unit"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"tests/integration"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">required_pull_request_reviews</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">required_approving_review_count</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">dismiss_stale_reviews</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">require_code_owner_reviews</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">restrictions</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">users</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">teams</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"security-team"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">enforce_admins</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">required_linear_history</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">allow_force_pushes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">allow_deletions</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">false</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="gitlab-protected-branches">GitLab Protected Branches<a href="https://pascal-nehlsen.de/blog/git-security-practices#gitlab-protected-branches" class="hash-link" aria-label="Direct link to GitLab Protected Branches" title="Direct link to GitLab Protected Branches" translate="no">​</a></h3>
<div class="language-ruby codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ruby codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token plain"># Via GitLab UI or API</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">POST /projects/:id/protected_branches</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">{</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  "name": "main",</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  "push_access_level": 0,  # No one</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  "merge_access_level": 30, # Developers</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  "unprotect_access_level": 40, # Maintainers</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  "allow_force_push": false,</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  "code_owner_approval_required": true</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-pre-commit-hooks-for-secret-detection">3. Pre-commit Hooks for Secret Detection<a href="https://pascal-nehlsen.de/blog/git-security-practices#3-pre-commit-hooks-for-secret-detection" class="hash-link" aria-label="Direct link to 3. Pre-commit Hooks for Secret Detection" title="Direct link to 3. Pre-commit Hooks for Secret Detection" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="setup-pre-commit-framework">Setup pre-commit Framework<a href="https://pascal-nehlsen.de/blog/git-security-practices#setup-pre-commit-framework" class="hash-link" aria-label="Direct link to Setup pre-commit Framework" title="Direct link to Setup pre-commit Framework" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Install</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">pip </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> pre-commit</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Create .pre-commit-config.yaml</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">cat</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> .pre-commit-config.yaml </span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;&lt;</span><span class="token string" style="color:rgb(173, 219, 103)">EOF</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">repos:</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  # Detect secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  - repo: https://github.com/Yelp/detect-secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">    rev: v1.4.0</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">    hooks:</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">      - id: detect-secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">        args: ['--baseline', '.secrets.baseline']</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  # Git-secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  - repo: https://github.com/awslabs/git-secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">    rev: master</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">    hooks:</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">      - id: git-secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  # Check for large files</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  - repo: https://github.com/pre-commit/pre-commit-hooks</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">    rev: v4.5.0</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">    hooks:</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">      - id: check-added-large-files</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">        args: ['--maxkb=500']</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">      - id: check-merge-conflict</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">      - id: check-yaml</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">      - id: check-json</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">      - id: trailing-whitespace</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">      - id: end-of-file-fixer</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  # Gitleaks for secret scanning</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  - repo: https://github.com/gitleaks/gitleaks</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">    rev: v8.18.0</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">    hooks:</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">      - id: gitleaks</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">EOF</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Install hooks</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">pre-commit </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Run on all files</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">pre-commit run --all-files</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="custom-pre-commit-hook">Custom Pre-commit Hook<a href="https://pascal-nehlsen.de/blog/git-security-practices#custom-pre-commit-hook" class="hash-link" aria-label="Direct link to Custom Pre-commit Hook" title="Direct link to Custom Pre-commit Hook" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token shebang important">#!/bin/bash</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># .git/hooks/pre-commit</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"Running security checks..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Check for AWS credentials</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">grep</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-r</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"AKIA[0-9A-Z]{16}"</span><span class="token plain"> --exclude-dir</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">.git </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">then</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"ERROR: AWS Access Key detected!"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">exit</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">fi</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Check for private keys</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">grep</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-r</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"BEGIN.*PRIVATE KEY"</span><span class="token plain"> --exclude-dir</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">.git </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">then</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"ERROR: Private key detected!"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">exit</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">fi</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Check for common password patterns</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">grep</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-ri</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"password\s*=\s*['</span><span class="token string entity" style="color:rgb(173, 219, 103)">\"</span><span class="token string" style="color:rgb(173, 219, 103)">]\w"</span><span class="token plain"> --exclude-dir</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">.git </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">then</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"ERROR: Hardcoded password detected!"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">exit</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">fi</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Check for Stripe keys</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">grep</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-r</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"sk_live_[0-9a-zA-Z]{24}"</span><span class="token plain"> --exclude-dir</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">.git </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">then</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"ERROR: Stripe secret key detected!"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">exit</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">fi</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"All security checks passed"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">exit</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-cleaning-git-history">4. Cleaning Git History<a href="https://pascal-nehlsen.de/blog/git-security-practices#4-cleaning-git-history" class="hash-link" aria-label="Direct link to 4. Cleaning Git History" title="Direct link to 4. Cleaning Git History" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="remove-sensitive-file-from-history">Remove Sensitive File from History<a href="https://pascal-nehlsen.de/blog/git-security-practices#remove-sensitive-file-from-history" class="hash-link" aria-label="Direct link to Remove Sensitive File from History" title="Direct link to Remove Sensitive File from History" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Using BFG Repo-Cleaner (faster than git filter-branch)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">wget</span><span class="token plain"> https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Remove file</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">java</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-jar</span><span class="token plain"> bfg-1.14.0.jar --delete-files secrets.env</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Remove passwords from all files</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">java</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-jar</span><span class="token plain"> bfg-1.14.0.jar --replace-text passwords.txt</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Clean up</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> reflog expire </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--expire</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">now </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--all</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> gc </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--prune</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">now </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--aggressive</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Force push (coordinate with team!)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> push </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--force</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-git-filter-repo">Using git-filter-repo<a href="https://pascal-nehlsen.de/blog/git-security-practices#using-git-filter-repo" class="hash-link" aria-label="Direct link to Using git-filter-repo" title="Direct link to Using git-filter-repo" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Install</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">pip </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> git-filter-repo</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Remove specific file</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> filter-repo </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--path</span><span class="token plain"> secrets.env --invert-paths</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Remove by pattern</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> filter-repo --path-glob </span><span class="token string" style="color:rgb(173, 219, 103)">'*.key'</span><span class="token plain"> --invert-paths</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Replace text</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'password123==&gt;***REMOVED***'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> replacements.txt</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> filter-repo --replace-text replacements.txt</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-git-repository-scanning">5. Git Repository Scanning<a href="https://pascal-nehlsen.de/blog/git-security-practices#5-git-repository-scanning" class="hash-link" aria-label="Direct link to 5. Git Repository Scanning" title="Direct link to 5. Git Repository Scanning" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-gitleaks">Using Gitleaks<a href="https://pascal-nehlsen.de/blog/git-security-practices#using-gitleaks" class="hash-link" aria-label="Direct link to Using Gitleaks" title="Direct link to Using Gitleaks" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Install</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">brew </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> gitleaks  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># macOS</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># or</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">wget</span><span class="token plain"> https://github.com/gitleaks/gitleaks/releases/download/v8.18.0/gitleaks_8.18.0_linux_x64.tar.gz</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Scan current repository</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">gitleaks detect </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--verbose</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Scan specific commit range</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">gitleaks detect --log-opts</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"HEAD^..HEAD"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Generate report</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">gitleaks detect --report-path gitleaks-report.json --report-format json</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-trufflehog">Using TruffleHog<a href="https://pascal-nehlsen.de/blog/git-security-practices#using-trufflehog" class="hash-link" aria-label="Direct link to Using TruffleHog" title="Direct link to Using TruffleHog" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Install</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">pip </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> truffleHog</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Scan repository</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">trufflehog </span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> https://github.com/your-org/your-repo</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Scan local repo</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">trufflehog filesystem /path/to/repo</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Scan since specific commit</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">trufflehog </span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> file:///path/to/repo --since-commit abcd1234</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="cicd-integration">CI/CD Integration<a href="https://pascal-nehlsen.de/blog/git-security-practices#cicd-integration" class="hash-link" aria-label="Direct link to CI/CD Integration" title="Direct link to CI/CD Integration" translate="no">​</a></h3>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># .gitlab-ci.yml</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule">security:gitleaks</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">stage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> security</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> zricethezav/gitleaks</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">latest</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">script</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> gitleaks detect </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">verbose </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">report</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">path gitleaks</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">report.json</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">artifacts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">reports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule">secret_detection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> gitleaks</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">report.json</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">paths</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> gitleaks</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">report.json</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">allow_failure</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule">security:trufflehog</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">stage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> security</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> python</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token number" style="color:rgb(247, 140, 108)">3.11</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">script</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> pip install truffleHog</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> trufflehog filesystem . </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">json </span><span class="token punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"> trufflehog</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">report.json</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">artifacts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">paths</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> trufflehog</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">report.json</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-secure-git-workflows">6. Secure Git Workflows<a href="https://pascal-nehlsen.de/blog/git-security-practices#6-secure-git-workflows" class="hash-link" aria-label="Direct link to 6. Secure Git Workflows" title="Direct link to 6. Secure Git Workflows" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="gitflow-with-security-gates">Gitflow with Security Gates<a href="https://pascal-nehlsen.de/blog/git-security-practices#gitflow-with-security-gates" class="hash-link" aria-label="Direct link to Gitflow with Security Gates" title="Direct link to Gitflow with Security Gates" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token plain">main (protected)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  ├── develop (protected)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  │   ├── feature/user-auth (requires: SAST, secrets scan)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  │   ├── feature/payment (requires: SAST, DAST, security review)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  │   └── bugfix/login-issue</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  ├── release/v1.2.0 (requires: full security scan)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  └── hotfix/critical-vuln (emergency process)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="security-checks-per-branch-type">Security Checks Per Branch Type<a href="https://pascal-nehlsen.de/blog/git-security-practices#security-checks-per-branch-type" class="hash-link" aria-label="Direct link to Security Checks Per Branch Type" title="Direct link to Security Checks Per Branch Type" translate="no">​</a></h3>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># .gitlab-ci.yml</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule">workflow</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">rules</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">if</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'$CI_COMMIT_BRANCH =~ /^feature\/.*$/'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule">variables</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule">SECURITY_LEVEL</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"standard"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">if</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'$CI_COMMIT_BRANCH =~ /^release\/.*$/'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule">variables</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule">SECURITY_LEVEL</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"full"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">if</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'$CI_COMMIT_BRANCH == "main"'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule">variables</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule">SECURITY_LEVEL</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"full"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule">security:scan</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">script</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">|</span><span class="token scalar string" style="color:rgb(173, 219, 103)"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token scalar string" style="color:rgb(173, 219, 103)">      if [ "$SECURITY_LEVEL" == "full" ]; then</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token scalar string" style="color:rgb(173, 219, 103)">        echo "Running full security scan"</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token scalar string" style="color:rgb(173, 219, 103)">        gitleaks detect</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token scalar string" style="color:rgb(173, 219, 103)">        trivy fs . --severity HIGH,CRITICAL</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token scalar string" style="color:rgb(173, 219, 103)">        snyk test</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token scalar string" style="color:rgb(173, 219, 103)">      else</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token scalar string" style="color:rgb(173, 219, 103)">        echo "Running standard security scan"</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token scalar string" style="color:rgb(173, 219, 103)">        gitleaks detect</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token scalar string" style="color:rgb(173, 219, 103)">      fi</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-access-control--permissions">7. Access Control &amp; Permissions<a href="https://pascal-nehlsen.de/blog/git-security-practices#7-access-control--permissions" class="hash-link" aria-label="Direct link to 7. Access Control &amp; Permissions" title="Direct link to 7. Access Control &amp; Permissions" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="github-teams-structure">GitHub Teams Structure<a href="https://pascal-nehlsen.de/blog/git-security-practices#github-teams-structure" class="hash-link" aria-label="Direct link to GitHub Teams Structure" title="Direct link to GitHub Teams Structure" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token plain">Organization</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">├── Admins (full access)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">├── Security Team (all repos, branch protection)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">├── Developers</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">│   ├── Backend Team (backend repos, write access)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">│   ├── Frontend Team (frontend repos, write access)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">│   └── DevOps Team (infra repos, write access)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">└── External Contributors (read-only, can fork)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="codeowners-file">CODEOWNERS File<a href="https://pascal-nehlsen.de/blog/git-security-practices#codeowners-file" class="hash-link" aria-label="Direct link to CODEOWNERS File" title="Direct link to CODEOWNERS File" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># .github/CODEOWNERS</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Default owners for everything</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">* @org/developers</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Security-sensitive files require security team review</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/security/ @org/security-team</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/.github/ @org/security-team @org/devops</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/Dockerfile @org/security-team @org/devops</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/docker-compose.yml @org/security-team @org/devops</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Infrastructure code requires DevOps review</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/terraform/ @org/devops @org/security-team</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/kubernetes/ @org/devops @org/security-team</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/.gitlab-ci.yml @org/devops</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Backend requires backend team</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/backend/ @org/backend-team</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/api/ @org/backend-team</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Frontend requires frontend team</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/frontend/ @org/frontend-team</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/web/ @org/frontend-team</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Database migrations require multiple approvals</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">/migrations/ @org/backend-team @org/database-admins</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Critical security files require admin approval</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">secrets.yml @org/admins @org/security-team</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">.env.* @org/admins @org/security-team</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="8-git-audit-logging">8. Git Audit Logging<a href="https://pascal-nehlsen.de/blog/git-security-practices#8-git-audit-logging" class="hash-link" aria-label="Direct link to 8. Git Audit Logging" title="Direct link to 8. Git Audit Logging" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="monitor-git-operations">Monitor Git Operations<a href="https://pascal-nehlsen.de/blog/git-security-practices#monitor-git-operations" class="hash-link" aria-label="Direct link to Monitor Git Operations" title="Direct link to Monitor Git Operations" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># git_audit_logger.py</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> git</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> json</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> logging</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> datetime </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> datetime</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">GitAuditLogger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">__init__</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> repo_path</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">repo </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> git</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Repo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">repo_path</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">setup_logging</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setup_logging</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        logging</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">basicConfig</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            filename</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">'git-audit.log'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            level</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">logging</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">INFO</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token builtin" style="color:rgb(130, 170, 255)">format</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">'%(asctime)s - %(message)s'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">log_commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""Log commit details"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        log_entry </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token string" style="color:rgb(173, 219, 103)">'action'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'commit'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token string" style="color:rgb(173, 219, 103)">'sha'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">hexsha</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token string" style="color:rgb(173, 219, 103)">'author'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">author</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token string" style="color:rgb(173, 219, 103)">'email'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">author</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">email</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token string" style="color:rgb(173, 219, 103)">'message'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">message</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token string" style="color:rgb(173, 219, 103)">'timestamp'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">committed_datetime</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">isoformat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token string" style="color:rgb(173, 219, 103)">'files_changed'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">len</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">stats</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">files</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token string" style="color:rgb(173, 219, 103)">'insertions'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">stats</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">total</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'insertions'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token string" style="color:rgb(173, 219, 103)">'deletions'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">stats</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">total</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'deletions'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        logging</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">info</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">dumps</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">log_entry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">audit_recent_commits</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> days</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token number" style="color:rgb(247, 140, 108)">7</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""Audit commits from last N days"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        since </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> datetime</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">-</span><span class="token plain"> timedelta</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">days</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">days</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">for</span><span class="token plain"> commit </span><span class="token keyword" style="color:rgb(127, 219, 202)">in</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">repo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">iter_commits</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">since</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">since</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">log_commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">detect_suspicious_activity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""Detect suspicious patterns"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        alerts </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">for</span><span class="token plain"> commit </span><span class="token keyword" style="color:rgb(127, 219, 202)">in</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">repo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">iter_commits</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">max_count</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token number" style="color:rgb(247, 140, 108)">100</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Large deletions (potential data destruction)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">stats</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">total</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'deletions'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                alerts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">append</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                    </span><span class="token string" style="color:rgb(173, 219, 103)">'severity'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'high'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                    </span><span class="token string" style="color:rgb(173, 219, 103)">'type'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'large_deletion'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                    </span><span class="token string" style="color:rgb(173, 219, 103)">'commit'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">hexsha</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                    </span><span class="token string" style="color:rgb(173, 219, 103)">'author'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">author</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">email</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Commits at unusual hours (potential compromise)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            hour </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">committed_datetime</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">hour</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> hour </span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">6</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">or</span><span class="token plain"> hour </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">22</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                alerts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">append</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                    </span><span class="token string" style="color:rgb(173, 219, 103)">'severity'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'medium'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                    </span><span class="token string" style="color:rgb(173, 219, 103)">'type'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'unusual_hour'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                    </span><span class="token string" style="color:rgb(173, 219, 103)">'commit'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">hexsha</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                    </span><span class="token string" style="color:rgb(173, 219, 103)">'time'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">committed_datetime</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">isoformat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> alerts</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Usage</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">audit </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> GitAuditLogger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'/path/to/repo'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">audit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">audit_recent_commits</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">days</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token number" style="color:rgb(247, 140, 108)">30</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">alerts </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> audit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">detect_suspicious_activity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">for</span><span class="token plain"> alert </span><span class="token keyword" style="color:rgb(127, 219, 202)">in</span><span class="token plain"> alerts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"WARNING: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">alert</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string-interpolation interpolation string" style="color:rgb(173, 219, 103)">'severity'</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token string-interpolation interpolation">upper</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">alert</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string-interpolation interpolation string" style="color:rgb(173, 219, 103)">'type'</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)"> - </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">alert</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string-interpolation interpolation string" style="color:rgb(173, 219, 103)">'commit'</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="9-secure-git-configuration">9. Secure Git Configuration<a href="https://pascal-nehlsen.de/blog/git-security-practices#9-secure-git-configuration" class="hash-link" aria-label="Direct link to 9. Secure Git Configuration" title="Direct link to 9. Secure Git Configuration" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="global-security-settings">Global Security Settings<a href="https://pascal-nehlsen.de/blog/git-security-practices#global-security-settings" class="hash-link" aria-label="Direct link to Global Security Settings" title="Direct link to Global Security Settings" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Prevent accidental pushes to wrong remote</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> push.default simple</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Always use SSH instead of HTTPS</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> url.</span><span class="token string" style="color:rgb(173, 219, 103)">"git@github.com:"</span><span class="token plain">.insteadOf </span><span class="token string" style="color:rgb(173, 219, 103)">"https://github.com/"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Enable credential helper (cached credentials)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> credential.helper </span><span class="token string" style="color:rgb(173, 219, 103)">'cache --timeout=3600'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Auto-fetch with prune</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> fetch.prune </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Show status in short format</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> status.short </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Use rebase instead of merge for pulls</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> pull.rebase </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Sign all tags by default</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><span class="token plain"> tag.gpgSign </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="repository-specific-settings">Repository-Specific Settings<a href="https://pascal-nehlsen.de/blog/git-security-practices#repository-specific-settings" class="hash-link" aria-label="Direct link to Repository-Specific Settings" title="Direct link to Repository-Specific Settings" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Inside repository</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">cd</span><span class="token plain"> your-repo</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Require signed commits</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config commit.gpgsign </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Set up hooks directory</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config core.hooksPath .githooks</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Enable fsck on receive</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> config receive.fsckObjects </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="security-checklist">Security Checklist<a href="https://pascal-nehlsen.de/blog/git-security-practices#security-checklist" class="hash-link" aria-label="Direct link to Security Checklist" title="Direct link to Security Checklist" translate="no">​</a></h2>
<ul class="contains-task-list containsTaskList_mC6p">
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Enable GPG commit signing</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Configure branch protection rules</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Set up pre-commit hooks for secret detection</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Add CODEOWNERS file</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Enable 2FA for all team members</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Regular repository scanning (gitleaks, trufflehog)</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Audit git access logs monthly</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Limit force push permissions</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Review and rotate SSH keys annually</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Train team on git security best practices</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Document incident response for leaked credentials</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Use SSH keys instead of passwords</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Implement security gates in CI/CD</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="emergency-leaked-credentials">Emergency: Leaked Credentials<a href="https://pascal-nehlsen.de/blog/git-security-practices#emergency-leaked-credentials" class="hash-link" aria-label="Direct link to Emergency: Leaked Credentials" title="Direct link to Emergency: Leaked Credentials" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token shebang important">#!/bin/bash</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># emergency-git-cleanup.sh</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"EMERGENCY: Credential Leak Response"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 1. Revoke compromised credentials immediately</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[1/5] Revoking credentials..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Call your secrets management API</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 2. Scan entire git history</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[2/5] Scanning git history..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">gitleaks detect </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--verbose</span><span class="token plain"> --log-opts</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"--all"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 3. Remove secrets from history</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[3/5] Cleaning git history..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">java</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-jar</span><span class="token plain"> bfg.jar --replace-text passwords.txt</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> reflog expire </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--expire</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">now </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--all</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> gc </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--prune</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">now </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--aggressive</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 4. Notify team</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[4/5] Notifying team..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">gh api /repos/:owner/:repo/issues </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-X</span><span class="token plain"> POST </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-f</span><span class="token plain"> </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">title</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"Security Incident: Credentials Leaked"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-f</span><span class="token plain"> </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">body</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"Immediate action required. Check Slack for details."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 5. Force push (DANGEROUS - coordinate first!)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[5/5] Force pushing clean history..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">read</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-p</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"Are you sure you want to force push? (yes/no): "</span><span class="token plain"> confirm</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"</span><span class="token string variable" style="color:rgb(214, 222, 235)">$confirm</span><span class="token string" style="color:rgb(173, 219, 103)">"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"yes"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">then</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> push </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--force</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--all</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> push </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--force</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--tags</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">fi</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"Emergency response complete"</span><br></div></code></pre></div></div>
<p>Next week: <strong>Kubernetes Security Deep Dive</strong></p>
<hr>
<p><em>Securing your Git workflows? Share your tips on <a href="https://github.com/PascalNehlsen" target="_blank" rel="noopener noreferrer" class="">GitHub</a>!</em></p>]]></content>
        <author>
            <name>Pascal Nehlsen</name>
            <email>mail@pascal-nehlsen.de</email>
            <uri>https://github.com/PascalNehlsen</uri>
        </author>
        <category label="Git" term="Git"/>
        <category label="DevSecOps" term="DevSecOps"/>
        <category label="Secrets" term="Secrets"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Secrets Management Done Right - No More Hardcoded Passwords]]></title>
        <id>https://pascal-nehlsen.de/blog/secrets-management-done-right</id>
        <link href="https://pascal-nehlsen.de/blog/secrets-management-done-right"/>
        <updated>2024-04-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Why .env files are a local-development convenience and not a secrets strategy, and what to use instead: a secrets manager, short-lived credentials, and scanning before the commit lands.]]></summary>
        <content type="html"><![CDATA[<p>Hardcoded secrets are a security nightmare. Here's how I implemented proper secrets management across development, staging, and production.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-50000-lesson">The $50,000 Lesson<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#the-50000-lesson" class="hash-link" aria-label="Direct link to The $50,000 Lesson" title="Direct link to The $50,000 Lesson" translate="no">​</a></h2>
<p>A developer accidentally committed AWS credentials to a public GitHub repo. Within <strong>4 minutes</strong>, attackers spun up EC2 instances for crypto mining. The bill: <strong>$50,847</strong> before we caught it.</p>
<p>This is why secrets management matters.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-problems-we-faced">The Problems We Faced<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#the-problems-we-faced" class="hash-link" aria-label="Direct link to The Problems We Faced" title="Direct link to The Problems We Faced" translate="no">​</a></h2>
<ol>
<li class=""><strong>Hardcoded secrets</strong> in source code</li>
<li class=""><strong>Secrets in environment variables</strong> (visible in logs)</li>
<li class=""><strong>Shared passwords</strong> across team members</li>
<li class=""><strong>No rotation policy</strong></li>
<li class=""><strong>No audit trail</strong> of secret access</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-1-hashicorp-vault">Solution 1: HashiCorp Vault<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#solution-1-hashicorp-vault" class="hash-link" aria-label="Direct link to Solution 1: HashiCorp Vault" title="Direct link to Solution 1: HashiCorp Vault" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="setup">Setup<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#setup" class="hash-link" aria-label="Direct link to Setup" title="Direct link to Setup" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Install Vault</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">wget</span><span class="token plain"> https://releases.hashicorp.com/vault/1.15.0/vault_1.15.0_linux_amd64.zip</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">unzip</span><span class="token plain"> vault_1.15.0_linux_amd64.zip</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">sudo</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">mv</span><span class="token plain"> vault /usr/local/bin/</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Start Vault in dev mode (for testing)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">vault server </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-dev</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Export Vault address</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">export</span><span class="token plain"> </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">VAULT_ADDR</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">'http://127.0.0.1:8200'</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="store-secrets">Store Secrets<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#store-secrets" class="hash-link" aria-label="Direct link to Store Secrets" title="Direct link to Store Secrets" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Store database credentials</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">vault kv put secret/database/prod </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">username</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"db_admin"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">password</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"</span><span class="token string variable" style="color:rgb(214, 222, 235)">$(</span><span class="token string variable" style="color:rgb(214, 222, 235)">openssl rand </span><span class="token string variable parameter variable" style="color:rgb(214, 222, 235)">-base64</span><span class="token string variable" style="color:rgb(214, 222, 235)"> </span><span class="token string variable number" style="color:rgb(247, 140, 108)">32</span><span class="token string variable" style="color:rgb(214, 222, 235)">)</span><span class="token string" style="color:rgb(173, 219, 103)">"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">host</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"prod-db.company.com"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">port</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"5432"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Store API keys</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">vault kv put secret/api/stripe </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">public_key</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"pk_live_xxx"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">secret_key</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"sk_live_yyy"</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="retrieve-secrets-in-python">Retrieve Secrets in Python<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#retrieve-secrets-in-python" class="hash-link" aria-label="Direct link to Retrieve Secrets in Python" title="Direct link to Retrieve Secrets in Python" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> hvac</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> os</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">SecretsManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">__init__</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> hvac</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            url</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getenv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'VAULT_ADDR'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            token</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getenv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'VAULT_TOKEN'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">get_db_credentials</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> env</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">'prod'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""Get database credentials from Vault"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">try</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            secret </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">secrets</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">kv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">v2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">read_secret_version</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                path</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f'database/</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">env</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'data'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'data'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">except</span><span class="token plain"> Exception </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token keyword" style="color:rgb(127, 219, 202)">raise</span><span class="token plain"> ValueError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"Failed to retrieve secrets: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">e</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">get_api_key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> service</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""Get API key for specific service"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        secret </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">secrets</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">kv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">v2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">read_secret_version</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            path</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f'api/</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">service</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'data'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'data'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'secret_key'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Usage</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">secrets </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> SecretsManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">db_creds </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> secrets</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_db_credentials</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'prod'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">stripe_key </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> secrets</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_api_key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'stripe'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Connect to database</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> psycopg2</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">conn </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> psycopg2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    host</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">db_creds</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'host'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    port</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">db_creds</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'port'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    user</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">db_creds</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'username'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    password</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">db_creds</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'password'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-2-kubernetes-secrets">Solution 2: Kubernetes Secrets<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#solution-2-kubernetes-secrets" class="hash-link" aria-label="Direct link to Solution 2: Kubernetes Secrets" title="Direct link to Solution 2: Kubernetes Secrets" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-secret-from-literal">Create Secret from Literal<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#create-secret-from-literal" class="hash-link" aria-label="Direct link to Create Secret from Literal" title="Direct link to Create Secret from Literal" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token plain">kubectl create secret generic db-credentials </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  --from-literal</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">username</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">admin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  --from-literal</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">password</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token variable" style="color:rgb(214, 222, 235)">$(</span><span class="token variable" style="color:rgb(214, 222, 235)">openssl rand </span><span class="token variable parameter variable" style="color:rgb(214, 222, 235)">-base64</span><span class="token variable" style="color:rgb(214, 222, 235)"> </span><span class="token variable number" style="color:rgb(247, 140, 108)">32</span><span class="token variable" style="color:rgb(214, 222, 235)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--namespace</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">production</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-secret-from-file">Create Secret from File<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#create-secret-from-file" class="hash-link" aria-label="Direct link to Create Secret from File" title="Direct link to Create Secret from File" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Create secret file</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">cat</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> db-secret.yaml </span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;&lt;</span><span class="token string" style="color:rgb(173, 219, 103)">EOF</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">apiVersion: v1</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">kind: Secret</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">metadata:</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  name: database-credentials</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  namespace: production</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">type: Opaque</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">stringData:</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  username: db_admin</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  password: </span><span class="token string variable" style="color:rgb(214, 222, 235)">$(</span><span class="token string variable" style="color:rgb(214, 222, 235)">openssl rand </span><span class="token string variable parameter variable" style="color:rgb(214, 222, 235)">-base64</span><span class="token string variable" style="color:rgb(214, 222, 235)"> </span><span class="token string variable number" style="color:rgb(247, 140, 108)">32</span><span class="token string variable" style="color:rgb(214, 222, 235)">)</span><span class="token string" style="color:rgb(173, 219, 103)"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">  connection-string: "postgresql://db_admin:password@prod-db:5432/myapp"</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">EOF</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Apply secret</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">kubectl apply </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-f</span><span class="token plain"> db-secret.yaml</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-secrets-in-deployment">Use Secrets in Deployment<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#use-secrets-in-deployment" class="hash-link" aria-label="Direct link to Use Secrets in Deployment" title="Direct link to Use Secrets in Deployment" translate="no">​</a></h3>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> apps/v1</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Deployment</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> backend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">app</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">replicas</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">3</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule">template</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule">containers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> app</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> myapp</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">latest</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Environment variable from secret</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> DATABASE_USERNAME</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token key atrule">valueFrom</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token key atrule">secretKeyRef</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">              </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> database</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">credentials</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">              </span><span class="token key atrule">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> username</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> DATABASE_PASSWORD</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token key atrule">valueFrom</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token key atrule">secretKeyRef</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">              </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> database</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">credentials</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">              </span><span class="token key atrule">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> password</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Mount entire secret as files</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule">volumeMounts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">volume</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token key atrule">mountPath</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> /etc/secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token key atrule">readOnly</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule">volumes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">volume</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule">secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token key atrule">secretName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> database</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">credentials</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="read-mounted-secrets-in-python">Read Mounted Secrets in Python<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#read-mounted-secrets-in-python" class="hash-link" aria-label="Direct link to Read Mounted Secrets in Python" title="Direct link to Read Mounted Secrets in Python" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">read_secret_file</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">secret_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""Read secret from mounted volume"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    secret_path </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"/etc/secrets/</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">secret_name</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">with</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">open</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">secret_path</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'r'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> f</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> f</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">read</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">strip</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Usage</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">db_username </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> read_secret_file</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'username'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">db_password </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> read_secret_file</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'password'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-3-aws-secrets-manager">Solution 3: AWS Secrets Manager<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#solution-3-aws-secrets-manager" class="hash-link" aria-label="Direct link to Solution 3: AWS Secrets Manager" title="Direct link to Solution 3: AWS Secrets Manager" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="store-secret">Store Secret<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#store-secret" class="hash-link" aria-label="Direct link to Store Secret" title="Direct link to Store Secret" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token plain">aws secretsmanager create-secret </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--name</span><span class="token plain"> prod/database/credentials </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  --secret-string </span><span class="token string" style="color:rgb(173, 219, 103)">'{"username":"admin","password":"secure_password","host":"prod-db.aws.com"}'</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="retrieve-in-python">Retrieve in Python<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#retrieve-in-python" class="hash-link" aria-label="Direct link to Retrieve in Python" title="Direct link to Retrieve in Python" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> boto3</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> json</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> botocore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">exceptions </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> ClientError</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">AWSSecretsManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">__init__</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> region</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">'us-east-1'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> boto3</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'secretsmanager'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> region_name</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">region</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">get_secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> secret_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""Retrieve secret from AWS Secrets Manager"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">try</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            response </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_secret_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">SecretId</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">secret_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">loads</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'SecretString'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">except</span><span class="token plain"> ClientError </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'Error'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'Code'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'ResourceNotFoundException'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">                </span><span class="token keyword" style="color:rgb(127, 219, 202)">raise</span><span class="token plain"> ValueError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"Secret </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">secret_name</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)"> not found"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            </span><span class="token keyword" style="color:rgb(127, 219, 202)">raise</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">rotate_secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> secret_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""Trigger secret rotation"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">rotate_secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            SecretId</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">secret_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">            RotationLambdaARN</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">'arn:aws:lambda:region:account:function:rotate-secret'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Usage</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">sm </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> AWSSecretsManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">db_creds </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> sm</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'prod/database/credentials'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"Connecting to </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">db_creds</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string-interpolation interpolation string" style="color:rgb(173, 219, 103)">'host'</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)"> as </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">db_creds</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string-interpolation interpolation string" style="color:rgb(173, 219, 103)">'username'</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-4-environment-specific-env-files">Solution 4: Environment-Specific .env Files<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#solution-4-environment-specific-env-files" class="hash-link" aria-label="Direct link to Solution 4: Environment-Specific .env Files" title="Direct link to Solution 4: Environment-Specific .env Files" translate="no">​</a></h2>
<p>For local development:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="project-structure">Project Structure<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#project-structure" class="hash-link" aria-label="Direct link to Project Structure" title="Direct link to Project Structure" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token plain">project/</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">├── .env.example        # Template (commit this)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">├── .env.development    # Local dev (DO NOT COMMIT)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">├── .env.staging        # Staging (DO NOT COMMIT)</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">└── .env.production     # Production (DO NOT COMMIT)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="envexample">.env.example<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#envexample" class="hash-link" aria-label="Direct link to .env.example" title="Direct link to .env.example" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Database Configuration</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">DATABASE_URL</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">postgresql://user:password@localhost:5432/dbname</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">DATABASE_POOL_SIZE</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token number" style="color:rgb(247, 140, 108)">10</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># API Keys</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">STRIPE_PUBLIC_KEY</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">pk_test_xxx</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">STRIPE_SECRET_KEY</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">sk_test_xxx</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># JWT Configuration</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">JWT_SECRET_KEY</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">your_secret_key_here</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">JWT_ALGORITHM</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">HS256</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Email Configuration</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">SMTP_HOST</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">smtp.gmail.com</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">SMTP_PORT</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token number" style="color:rgb(247, 140, 108)">587</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">SMTP_USERNAME</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">your_email@gmail.com</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">SMTP_PASSWORD</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">your_app_password</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="load-environment-variables">Load Environment Variables<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#load-environment-variables" class="hash-link" aria-label="Direct link to Load Environment Variables" title="Direct link to Load Environment Variables" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> dotenv </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> load_dotenv</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> os</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Load environment-specific config</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">env </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getenv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'APP_ENV'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'development'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">load_dotenv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f'.env.</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">env</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Validate required variables</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">required_vars </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token string" style="color:rgb(173, 219, 103)">'DATABASE_URL'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token string" style="color:rgb(173, 219, 103)">'JWT_SECRET_KEY'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token string" style="color:rgb(173, 219, 103)">'STRIPE_SECRET_KEY'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">missing_vars </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">var </span><span class="token keyword" style="color:rgb(127, 219, 202)">for</span><span class="token plain"> var </span><span class="token keyword" style="color:rgb(127, 219, 202)">in</span><span class="token plain"> required_vars </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">not</span><span class="token plain"> os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getenv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">var</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> missing_vars</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">raise</span><span class="token plain"> ValueError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"Missing required environment variables: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation string" style="color:rgb(173, 219, 103)">', '</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token string-interpolation interpolation">join</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation interpolation">missing_vars</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Access secrets</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">DATABASE_URL </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getenv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'DATABASE_URL'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">JWT_SECRET </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getenv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'JWT_SECRET_KEY'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="gitignore">.gitignore<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#gitignore" class="hash-link" aria-label="Direct link to .gitignore" title="Direct link to .gitignore" translate="no">​</a></h3>
<div class="language-gitignore codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-gitignore codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token plain"># Never commit these</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">.env</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">.env.*</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">!.env.example</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"># Secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">secrets/</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">*.key</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">*.pem</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">*.p12</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">*.pfx</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="secret-rotation-strategy">Secret Rotation Strategy<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#secret-rotation-strategy" class="hash-link" aria-label="Direct link to Secret Rotation Strategy" title="Direct link to Secret Rotation Strategy" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="automatic-rotation-aws">Automatic Rotation (AWS)<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#automatic-rotation-aws" class="hash-link" aria-label="Direct link to Automatic Rotation (AWS)" title="Direct link to Automatic Rotation (AWS)" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> boto3</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> datetime </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> datetime</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> timedelta</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">rotate_database_password</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">secret_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">    Rotate database password automatically</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">    Called by AWS Lambda on schedule</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">    """</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    sm </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> boto3</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'secretsmanager'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    rds </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> boto3</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'rds'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Get current secret</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    current </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> sm</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_secret_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">SecretId</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">secret_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    current_password </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">loads</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">current</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'SecretString'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'password'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Generate new password</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    new_password </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> generate_secure_password</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Update database</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    rds</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">modify_db_instance</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        DBInstanceIdentifier</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">'prod-db'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        MasterUserPassword</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">new_password</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Update secret</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    new_secret </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">loads</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">current</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'SecretString'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    new_secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'password'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> new_password</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    new_secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'rotated_at'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> datetime</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">isoformat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    sm</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">put_secret_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        SecretId</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">secret_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        SecretString</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">dumps</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">new_secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string" style="color:rgb(173, 219, 103)">"status"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"success"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"rotated_at"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> new_secret</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'rotated_at'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">generate_secure_password</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">length</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token number" style="color:rgb(247, 140, 108)">32</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(173, 219, 103)">"""Generate cryptographically secure password"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> string</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    alphabet </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ascii_letters </span><span class="token operator" style="color:rgb(127, 219, 202)">+</span><span class="token plain"> string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">digits </span><span class="token operator" style="color:rgb(127, 219, 202)">+</span><span class="token plain"> string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">punctuation</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">join</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">secrets</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">choice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">alphabet</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">for</span><span class="token plain"> _ </span><span class="token keyword" style="color:rgb(127, 219, 202)">in</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">range</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="detecting-leaked-secrets">Detecting Leaked Secrets<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#detecting-leaked-secrets" class="hash-link" aria-label="Direct link to Detecting Leaked Secrets" title="Direct link to Detecting Leaked Secrets" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pre-commit-hook-with-git-secrets">Pre-commit Hook with git-secrets<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#pre-commit-hook-with-git-secrets" class="hash-link" aria-label="Direct link to Pre-commit Hook with git-secrets" title="Direct link to Pre-commit Hook with git-secrets" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Install git-secrets</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">brew </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> git-secrets  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># macOS</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">sudo</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">apt-get</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> git-secrets  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Linux</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Setup for repository</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">cd</span><span class="token plain"> your-repo</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> secrets </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--install</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> secrets --register-aws</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Add custom patterns</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">git</span><span class="token plain"> secrets </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--add</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'password\s*=\s*["\'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain">S+</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">"\']'</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">git secrets --add 'api[_-]key\s*=\s*["</span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain">'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain">S+</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain">'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain">'</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pre-commit-hook-with-detect-secrets">Pre-commit Hook with detect-secrets<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#pre-commit-hook-with-detect-secrets" class="hash-link" aria-label="Direct link to Pre-commit Hook with detect-secrets" title="Direct link to Pre-commit Hook with detect-secrets" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Install</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">pip </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> detect-secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Generate baseline</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">detect-secrets scan </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> .secrets.baseline</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Add to .pre-commit-config.yaml</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">repos:</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  - repo: https://github.com/Yelp/detect-secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    rev: v1.4.0</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    hooks:</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      - id: detect-secrets</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        args: </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">'--baseline'</span><span class="token plain">, </span><span class="token string" style="color:rgb(173, 219, 103)">'.secrets.baseline'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="best-practices-checklist">Best Practices Checklist<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#best-practices-checklist" class="hash-link" aria-label="Direct link to Best Practices Checklist" title="Direct link to Best Practices Checklist" translate="no">​</a></h2>
<ul class="contains-task-list containsTaskList_mC6p">
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Never commit secrets</strong> to version control</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Use <strong>different secrets</strong> for dev/staging/prod</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Implement <strong>secret rotation</strong> (every 90 days)</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Enable <strong>audit logging</strong> for secret access</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Use <strong>short-lived tokens</strong> when possible</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Encrypt secrets <strong>at rest and in transit</strong></li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Implement <strong>least privilege access</strong></li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Set up <strong>secret scanning</strong> in CI/CD</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Have an <strong>incident response plan</strong> for leaked secrets</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Use <strong>managed services</strong> (Vault, AWS Secrets Manager) in production</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="emergency-response-secret-leaked">Emergency Response: Secret Leaked<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#emergency-response-secret-leaked" class="hash-link" aria-label="Direct link to Emergency Response: Secret Leaked" title="Direct link to Emergency Response: Secret Leaked" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#d6deeb"><span class="token shebang important">#!/bin/bash</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># emergency-secret-rotation.sh</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">SECRET_NAME</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token variable" style="color:rgb(214, 222, 235)">$1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"EMERGENCY SECRET ROTATION for </span><span class="token string variable" style="color:rgb(214, 222, 235)">$SECRET_NAME</span><span class="token string" style="color:rgb(173, 219, 103)">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 1. Revoke compromised secret immediately</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[1/5] Revoking compromised secret..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">aws secretsmanager rotate-secret --secret-id </span><span class="token variable" style="color:rgb(214, 222, 235)">$SECRET_NAME</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 2. Update all services</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[2/5] Updating Kubernetes secrets..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">kubectl delete secret </span><span class="token variable" style="color:rgb(214, 222, 235)">$SECRET_NAME</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">kubectl create secret generic </span><span class="token variable" style="color:rgb(214, 222, 235)">$SECRET_NAME</span><span class="token plain"> --from-literal</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">key</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token variable" style="color:rgb(214, 222, 235)">$(</span><span class="token variable" style="color:rgb(214, 222, 235)">generate_new_secret</span><span class="token variable" style="color:rgb(214, 222, 235)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 3. Rolling restart of all pods</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[3/5] Rolling restart..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">kubectl rollout restart deployment </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-n</span><span class="token plain"> production</span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 4. Audit access logs</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[4/5] Auditing access logs..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain">aws cloudtrail lookup-events --lookup-attributes </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">AttributeKey</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">ResourceName,AttributeValue</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token variable" style="color:rgb(214, 222, 235)">$SECRET_NAME</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># 5. Notify security team</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"[5/5] Notifying security team..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-X</span><span class="token plain"> POST </span><span class="token variable" style="color:rgb(214, 222, 235)">$SLACK_WEBHOOK</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-d</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"{</span><span class="token string entity" style="color:rgb(173, 219, 103)">\"</span><span class="token string" style="color:rgb(173, 219, 103)">text</span><span class="token string entity" style="color:rgb(173, 219, 103)">\"</span><span class="token string" style="color:rgb(173, 219, 103)">:</span><span class="token string entity" style="color:rgb(173, 219, 103)">\"</span><span class="token string" style="color:rgb(173, 219, 103)">Secret rotation completed for </span><span class="token string variable" style="color:rgb(214, 222, 235)">$SECRET_NAME</span><span class="token string entity" style="color:rgb(173, 219, 103)">\"</span><span class="token string" style="color:rgb(173, 219, 103)">}"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"Emergency rotation complete"</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cost-comparison">Cost Comparison<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#cost-comparison" class="hash-link" aria-label="Direct link to Cost Comparison" title="Direct link to Cost Comparison" translate="no">​</a></h2>
<table><thead><tr><th>Solution</th><th>Cost/Month</th><th>Pros</th><th>Cons</th></tr></thead><tbody><tr><td><strong>HashiCorp Vault</strong></td><td>Self-hosted: $0-500</td><td>Full control, flexible</td><td>Complex setup</td></tr><tr><td><strong>AWS Secrets Manager</strong></td><td>$0.40/secret + API calls</td><td>Managed, auto-rotation</td><td>AWS-only</td></tr><tr><td><strong>Azure Key Vault</strong></td><td>$0.03/10k operations</td><td>Managed, cheap</td><td>Azure-only</td></tr><tr><td><strong>Kubernetes Secrets</strong></td><td>Free</td><td>Built-in, simple</td><td>Basic features only</td></tr><tr><td><strong>Environment Variables</strong></td><td>Free</td><td>Very simple</td><td>Insecure, no rotation</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="resources">Resources<a href="https://pascal-nehlsen.de/blog/secrets-management-done-right#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" target="_blank" rel="noopener noreferrer" class="">OWASP Secrets Management Cheat Sheet</a></li>
<li class=""><a href="https://www.vaultproject.io/docs" target="_blank" rel="noopener noreferrer" class="">HashiCorp Vault Documentation</a></li>
<li class=""><a href="https://docs.aws.amazon.com/secretsmanager/latest/userguide/best-practices.html" target="_blank" rel="noopener noreferrer" class="">AWS Secrets Manager Best Practices</a></li>
</ul>
<p>Next: <strong>Implementing Zero Trust Architecture</strong></p>
<hr>
<p><em>Questions about secrets management? Let's discuss on <a href="https://github.com/PascalNehlsen" target="_blank" rel="noopener noreferrer" class="">GitHub</a>!</em></p>]]></content>
        <author>
            <name>Pascal Nehlsen</name>
            <email>mail@pascal-nehlsen.de</email>
            <uri>https://github.com/PascalNehlsen</uri>
        </author>
        <category label="Secrets" term="Secrets"/>
        <category label="DevSecOps" term="DevSecOps"/>
        <category label="CI/CD" term="CI/CD"/>
    </entry>
</feed>