<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Tyler Langlois</title>
    <description>The latest articles on Forem by Tyler Langlois (@tylerjl).</description>
    <link>https://forem.com/tylerjl</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F868817%2F9dc49efd-3e27-469c-ad19-2309c5cb0a1b.jpeg</url>
      <title>Forem: Tyler Langlois</title>
      <link>https://forem.com/tylerjl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tylerjl"/>
    <language>en</language>
    <item>
      <title>Managing Kubernetes Secrets with the External Secrets Operator and Doppler</title>
      <dc:creator>Tyler Langlois</dc:creator>
      <pubDate>Tue, 25 Oct 2022 15:48:28 +0000</pubDate>
      <link>https://forem.com/doppler/managing-kubernetes-secrets-with-the-external-secrets-operator-and-doppler-h90</link>
      <guid>https://forem.com/doppler/managing-kubernetes-secrets-with-the-external-secrets-operator-and-doppler-h90</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I9XAfdn5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5hzbzxxhk2psd0fqto6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I9XAfdn5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5hzbzxxhk2psd0fqto6.jpg" alt="Cover" width="880" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;API keys, credentials, and other types of sensitive information are the primary way your application calls external services and interacts with the world outside its own runtime. Ensuring that your secrets are secure is one of the most important operational tasks that you need to address, but it's not just rigorous security that's important providing an ergonomic, audited, and maintainable flow for the &lt;em&gt;management&lt;/em&gt; of those secrets is crucial as well. If managing credentials is confusing or difficult, mistakes can undo all of the careful work that goes into keeping secrets secure.&lt;/p&gt;

&lt;p&gt;Container orchestrators like Kubernetes offer helpful abstractions to address the need for sensitive values with native &lt;a href="https://kubernetes.io/docs/concepts/configuration/secret/"&gt;Secrets&lt;/a&gt;. However, a Kubernetes &lt;code&gt;Secret&lt;/code&gt; is a somewhat rudimentary object it lacks encryption by default and normally exists as a plain key/value within &lt;code&gt;etcd&lt;/code&gt;. By contrast, services like &lt;a href="https://www.vaultproject.io/"&gt;Vault&lt;/a&gt; or &lt;a href="https://www.doppler.com/"&gt;Doppler&lt;/a&gt; are intentionally designed to provide strong guarantees and well-defined access controls. Can we combine the operational power of Kubernetes with the assurance of a fully managed secret provider?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v4Ic_ivU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1666646955334/WHLpfqRIr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v4Ic_ivU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1666646955334/WHLpfqRIr.png" alt="Doppler Kubernetes External Secrets Operator" width="880" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes! The &lt;a href="https://github.com/external-secrets/external-secrets"&gt;External Secrets Operator&lt;/a&gt; is a Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/operator/"&gt;operator&lt;/a&gt; that bridges the gap between Kubernetes' native secret support and &lt;em&gt;external&lt;/em&gt; systems that provide a canonical source of truth for secret storage. It does this by leveraging &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/"&gt;custom resources&lt;/a&gt; that define how to retrieve external secrets in order to manage the lifecycle of &lt;code&gt;Secret&lt;/code&gt; resources in your Kubernetes cluster. In this tutorial, we'll use &lt;a href="https://www.doppler.com/"&gt;Doppler&lt;/a&gt; as the external secret provider to illustrate using external secrets in a real-world application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outcomes
&lt;/h2&gt;

&lt;p&gt;The end goal of this guide will be to leverage well-managed secrets in an application deployed in Kubernetes. To achieve this, we'll use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Kubernetes &lt;a href="https://github.com/external-secrets/external-secrets"&gt;External Secrets Operator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.doppler.com/"&gt;Doppler&lt;/a&gt; to store and manage external secrets&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://minikube.sigs.k8s.io/docs/"&gt;minikube&lt;/a&gt; or &lt;a href="https://kind.sigs.k8s.io/"&gt;kind&lt;/a&gt; for a local Kubernetes API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the conclusion of this tutorial, you'll understand how to store and manage secrets in Doppler, use those same secrets as native &lt;em&gt;Kubernetes&lt;/em&gt; secrets, and ultimately use them in a running application. Let's begin!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This article assumes that you'll follow along with your own Kubernetes cluster. You may choose to operate in an existing cluster (potentially within a sandboxed namespace), but if you'd like to use a sandbox instead, we suggest using either &lt;a href="https://minikube.sigs.k8s.io/docs/"&gt;minikube&lt;/a&gt; or &lt;a href="https://kind.sigs.k8s.io/"&gt;kind&lt;/a&gt; to create a local Kubernetes installation which will provide a safe environment for testing. In order to provide a clean and pristine environment, this tutorial will use &lt;a href="https://minikube.sigs.k8s.io/docs/"&gt;minikube&lt;/a&gt; as the Kubernetes target.&lt;/p&gt;

&lt;p&gt;In addition to a functional Kubernetes cluster, ensure that the following command-line tools are installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;helm&lt;/code&gt;, which we'll use to install the External Secrets Operator Kubernetes resources. Use the helm &lt;a href="https://helm.sh/docs/intro/quickstart/"&gt;quickstart guide&lt;/a&gt; to install helm.&lt;/li&gt;
&lt;li&gt;The Doppler command line utility &lt;code&gt;doppler&lt;/code&gt; using the Doppler &lt;a href="https://docs.doppler.com/docs/cli"&gt;CLI Guide&lt;/a&gt; documentation.

&lt;ul&gt;
&lt;li&gt;You will need to &lt;a href="https://dashboard.doppler.com/register"&gt;register for a Doppler account&lt;/a&gt; to create projects and store external secrets.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt; to interact with Kubernetes. &lt;code&gt;kubectl&lt;/code&gt; is available for a wide range of operating systems, and the &lt;a href="https://kubernetes.io/docs/tasks/tools/"&gt;Kubernetes documentation&lt;/a&gt; provides comprehensive installation guides for &lt;code&gt;kubectl&lt;/code&gt; and other tools as well.&lt;/li&gt;
&lt;li&gt;If you choose to use a local Kubernetes sandbox, install &lt;a href="https://minikube.sigs.k8s.io/docs/"&gt;minikube&lt;/a&gt; and follow the instructions to create a local instance of Kubernetes. This can be as simple as &lt;code&gt;minikube start&lt;/code&gt;, but consult the documentation if you need additional assistance.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;minikube&lt;/code&gt; bundles a version-compatible installation of &lt;code&gt;kubectl&lt;/code&gt; if you choose to use &lt;code&gt;minikube&lt;/code&gt; for this exercise. It's a handy time saver.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once installed, confirm that your environment is ready to go:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl version&lt;/code&gt; should confirm that &lt;code&gt;kubectl&lt;/code&gt; is present and communicating with the Kubernetes API successfully. If you aren't using &lt;code&gt;minikube&lt;/code&gt;, simply use the plain &lt;code&gt;kubectl&lt;/code&gt; command for the remainder of the tutorial.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ minikube kubectl -- version
Client Version: version.Info{Major:"1", Minor:"25", GitVersion:"v1.25.0", GitCommit:"a866cbe2e5bbaa01cfd5e969aa3e033f3282a8a2", GitTreeState:"clean", BuildDate:"2022-08-23T17:44:59Z", GoVersion:"go1.19", Compiler:"gc", Platform:"linux/amd64"}
Kustomize Version: v4.5.7
Server Version: version.Info{Major:"1", Minor:"25", GitVersion:"v1.25.0", GitCommit:"a866cbe2e5bbaa01cfd5e969aa3e033f3282a8a2", GitTreeState:"clean", BuildDate:"2022-08-23T17:38:15Z", GoVersion:"go1.19", Compiler:"gc", Platform:"linux/amd64"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;helm&lt;/code&gt; and &lt;code&gt;doppler&lt;/code&gt; commands should be available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ helm version
version.BuildInfo{Version:"v3.9.0", GitCommit:"7ceeda6c585217a19a1131663d8cd1f7d641b2a7", GitTreeState:"", GoVersion:"go1.17.13"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ doppler --version
v3.44.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the prerequisites installed, let's proceed with building and running our program.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Application
&lt;/h2&gt;

&lt;p&gt;Before we start creating secrets, let's begin by illustrating the external secrets workflow with a simple example service. The following guide will assume the use of &lt;code&gt;minikube&lt;/code&gt; to build and load an application container image, so if your Kubernetes environment is different, you may need to adapt the instructions to work with your specific container registry strategy.&lt;/p&gt;

&lt;p&gt;First, perform some initial steps to bootstrap a python &lt;a href="https://flask.palletsprojects.com/en/2.2.x/"&gt;Flask&lt;/a&gt; application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir -p ~/tmp/secret-sauce
$ cd ~/tmp/secret-sauce
$ git init
$ echo flask &amp;gt; requirements.txt
$ python3 -m venv venv
$ ./venv/bin/pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file named &lt;code&gt;app.py&lt;/code&gt; that contains the following simple web application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask
from os import environ

app = Flask( __name__ )

sauce = environ.get('SECRET_SAUCE')

@app.route("/")
def index():
    if sauce:
        return f"The secret sauce is: {sauce}!"
    else:
        return "You'll never find my secret sauce."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define a small &lt;code&gt;Dockerfile&lt;/code&gt; that defines how to build a container image for our application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "-m" , "flask", "run", "--host=0.0.0.0"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run this application locally with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./venv/bin/flask run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try accessing the running application at &lt;a href="http://localhost:5000"&gt;http://localhost:5000&lt;/a&gt; to see a response. The root route (&lt;code&gt;/&lt;/code&gt;) will render a static string when no secret is present in the environment but will print the secret when the indicated environment variable is defined. Don't print secrets in production! This application is just a demonstration of how to read the value in a real program.&lt;/p&gt;

&lt;p&gt;We're ready to load this application into Kubernetes. Assuming that you're following along with &lt;code&gt;minikube&lt;/code&gt;, proceed to build the application container in the Kubernetes node under the name "&lt;code&gt;app&lt;/code&gt;":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ minikube image build -t app .
...lots of output...
Successfully tagged app:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new Kubernetes &lt;code&gt;Deployment&lt;/code&gt; file named &lt;code&gt;deployment.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flask
  template:
    metadata:
      labels:
        app: flask
    spec:
      containers:
        - name: webapp
          image: app
          imagePullPolicy: Never
          ports:
            - containerPort: 5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take note of a few assumptions in this &lt;code&gt;Deployment&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;imagePullPolicy&lt;/code&gt; has been set to &lt;code&gt;Never&lt;/code&gt; because we're running a locally-built image. By default, Kubernetes would attempt to &lt;code&gt;pull&lt;/code&gt; the &lt;code&gt;app&lt;/code&gt; image, which doesn't exist. As previously mentioned, if you're following this tutorial in an environment other than &lt;code&gt;minikube&lt;/code&gt;, you may need to push the container image to a registry and adjust these settings slightly.&lt;/li&gt;
&lt;li&gt;We've exposed port &lt;code&gt;:5000&lt;/code&gt; which we can access later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Load this &lt;code&gt;Deployment&lt;/code&gt; into your running cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f deployment.yaml
deployment.apps/app created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, forward the port in another terminal window in order to access the running application in a simple tunnel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl port-forward deployment/app 5000:5000
Forwarding from 127.0.0.1:5000 -&amp;gt; 5000
Forwarding from [::1]:5000 -&amp;gt; 5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send a request to your Kubernetes application to see it in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:5000
You'll never find my secret sauce.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fantastic! Note that we've received the response that indicates no secret value has been injected into the environment. How can we add a secret to the application and see the &lt;em&gt;secret sauce&lt;/em&gt;?&lt;/p&gt;

&lt;h2&gt;
  
  
  Doppler
&lt;/h2&gt;

&lt;p&gt;By using &lt;a href="https://www.doppler.com/"&gt;Doppler&lt;/a&gt;, we can achieve a great deal of control over application secrets and manage them at each step of our application's lifecycle, from in our local development environment to within a Kubernetes workload.&lt;/p&gt;

&lt;p&gt;If you haven't signed up with Doppler, you can &lt;a href="https://dashboard.doppler.com/register"&gt;do so now&lt;/a&gt;. Once you have an account, proceed to use the &lt;code&gt;login&lt;/code&gt; command to set up your account locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ doppler login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setup Doppler for the demo application by defining a &lt;code&gt;doppler-template.yaml&lt;/code&gt; file in the root of the application directory. This YAML file defines a template that we can import to create a new Doppler project easily from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;projects:
  - name: secret-sauce
    description: Kubernetes demo app
    environments:
      - slug: dev
        name: Development
        configs:
          - slug: dev
      - slug: stg
        name: Staging
        configs:
          - slug: stg
      - slug: prd
        name: Production
        configs:
          - slug: prd
    secrets:
      dev:
        SECRET_SAUCE: tartar
      stg:
        SECRET_SAUCE: horseradish
      prd:
        SECRET_SAUCE: tzatziki
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter the directory in your shell and run the following &lt;code&gt;doppler&lt;/code&gt; command in order to bootstrap your Doppler project. This will create a new project called &lt;code&gt;secret-sauce&lt;/code&gt;, set up a few different environments, and load an initial secret value for &lt;code&gt;SECRET_SAUCE&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ doppler import
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see output similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┬──────────────┬─────────────────────┬──────────────────────────┐
│ ID           │ NAME         │ DESCRIPTION         │ CREATED AT               │
├──────────────┼──────────────┼─────────────────────┼──────────────────────────┤
│ secret-sauce │ secret-sauce │ Kubernetes demo app │ 2022-10-11T22:10:36.567Z │
└──────────────┴──────────────┴─────────────────────┴──────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;View the secrets for this project with &lt;code&gt;doppler secrets&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ doppler secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to some default variables that begin with &lt;code&gt;DOPPLER_&lt;/code&gt;, you'll also find the secret value we'd like to inject, &lt;code&gt;SECRET_SAUCE&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────┬──────────────┐
│ NAME                │ VALUE        │
├─────────────────────┼──────────────┤
│ DOPPLER_CONFIG      │ dev          │
│ DOPPLER_ENVIRONMENT │ dev          │
│ DOPPLER_PROJECT     │ secret-sauce │
│ SECRET_SAUCE        │ tartar       │
└─────────────────────┴──────────────┘   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run a quick test to confirm that our application behaves as expected when a secret is present in its environment variables. To do this, we can use the &lt;code&gt;doppler run&lt;/code&gt; command to easily inject the variable into our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ doppler run -- ./venv/bin/flask run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then issue a request to the listening port to see whether the response has changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:5000
The secret sauce is: tartar!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! Let's continue on to install the External Secrets Operator.&lt;/p&gt;

&lt;h2&gt;
  
  
  External Secrets
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/external-secrets/external-secrets"&gt;External Secrets Operator&lt;/a&gt; provides the translation layer between Kubernetes' native secrets and external secrets. The operator leverages &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/"&gt;custom resources&lt;/a&gt; in order to model external secrets, which it then retrieves as necessary and translates into native Kubernetes secrets that your workload can easily consume.&lt;/p&gt;

&lt;p&gt;The operator is provided as a Helm chart, so first add the upstream &lt;code&gt;external-secrets&lt;/code&gt; Helm repository to access the chart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ helm repo add external-secrets https://charts.external-secrets.io
external-secrets has been added to your repositories
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, install the chart into your Kubernetes cluster. The following command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instructs &lt;code&gt;helm&lt;/code&gt; to use the &lt;code&gt;external-secrets&lt;/code&gt; chart,&lt;/li&gt;
&lt;li&gt;passes &lt;code&gt;-n&lt;/code&gt; to install the chart into the &lt;code&gt;external-secrets&lt;/code&gt; namespace,&lt;/li&gt;
&lt;li&gt;creates the namespace as necessary with &lt;code&gt;--create-namespace&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;configures the requisite CRDs as well (&lt;code&gt;--set installCRDs=true&lt;/code&gt;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ helm install external-secrets \
     external-secrets/external-secrets \
     -n external-secrets \
     --create-namespace \
     --set installCRDs=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see output similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME: external-secrets
LAST DEPLOYED: Tue Oct 11 12:27:18 2022
NAMESPACE: external-secrets
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
external-secrets has been deployed successfully!

In order to begin using ExternalSecrets, you will need to set up a SecretStore
or ClusterSecretStore resource (for example, by creating a 'vault' SecretStore).

More information on the different types of SecretStores and how to configure them
can be found in our Github: https://github.com/external-secrets/external-secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this operator installed, we're now ready to set up Doppler to serve as the source for external secrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Doppler with Kubernetes
&lt;/h2&gt;

&lt;p&gt;The first step is to create a &lt;a href="////docs.doppler.com/docs/service-tokens"&gt;service token&lt;/a&gt; which serves as the authentication mechanism for the external secrets operator against Doppler. It should be stored inside of a generic Kubernetes secret that the operator will consume.&lt;/p&gt;

&lt;p&gt;You can generate and store the token in a single step with some fancy footwork in the shell to avoid copying and pasting the token around. The following command creates a new Doppler token and then immediately loads it into Kubernetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl create secret generic \
    doppler-token-auth-api \
    --from-literal dopplerToken=$(doppler configs tokens create --config prd doppler-auth-token --plain)
secret/doppler-token-auth-api created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we're passing the &lt;code&gt;--config prd&lt;/code&gt; flag to &lt;code&gt;doppler&lt;/code&gt; in order to create a token scoped to the &lt;code&gt;prd&lt;/code&gt; (production) configuration of our Doppler project. In our application directory, we defaulted to &lt;code&gt;dev&lt;/code&gt;, which has its own secrets. With this technique, we're only interacting with development secrets locally while loading production secrets into our container runtime, which keeps the risk of exposure for production secrets minimal.&lt;/p&gt;

&lt;p&gt;Next, create a &lt;code&gt;SecretStore&lt;/code&gt; CRD that points the operator at your Doppler service token secret. This step sets up Doppler as a source for external secrets that we can call upon later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: doppler-auth-api
spec:
  provider:
    doppler:
      auth:
        secretRef:
          dopplerToken:
            name: doppler-token-auth-api
            key: dopplerToken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the &lt;code&gt;SecretStore&lt;/code&gt; in Kubernetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f secretstore.yaml
secretstore.external-secrets.io/doppler-auth-api created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're ready to inject our secret sauce! A new &lt;code&gt;ExternalSecret&lt;/code&gt; is the necessary resource that enables us to synchronize one of our &lt;em&gt;Doppler&lt;/em&gt; secrets to a related generic &lt;em&gt;Kubernetes&lt;/em&gt; secret. Create a new file called &lt;code&gt;externalsecret.yaml&lt;/code&gt; with the following YAML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: secret-sauce
spec:
  secretStoreRef:
    kind: SecretStore
    name: doppler-auth-api

  target:
    name: secret-sauce

  data:
    - secretKey: SECRET_SAUCE
      remoteRef:
        key: SECRET_SAUCE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Load it into Kubernetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f externalsecret.yaml
externalsecret.external-secrets.io/secret-sauce created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can confirm that the secret was loaded by the operator by listing it with &lt;code&gt;kubectl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get secret secret-sauce
NAME TYPE DATA AGE
secret-sauce Opaque 1 3s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Success! Note that if you do not see the new secret, you can also inspect the External Secret Operator's logs to debug any issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl -n external-secrets logs -lapp.kubernetes.io/name=external-secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generic secrets can be seen in the Kubernetes dashboard as well. If you're using &lt;code&gt;minikube&lt;/code&gt;, you can quickly install and view the Kubernetes dashboard with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ minikube dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your browser will open to the dashboard landing page. You may use the left sidebar to navigate to the "Secrets" link to view your new secret:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UZ52PoAB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1666642558970/mVLa_og-O.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UZ52PoAB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1666642558970/mVLa_og-O.png" alt="Kubernetes Dashboard" width="880" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only task left to do is to consume the secret from our application. Here's an updated &lt;code&gt;Deployment&lt;/code&gt; that references the newly-created &lt;code&gt;Secret&lt;/code&gt;. Note the new &lt;code&gt;env&lt;/code&gt; key, which injects the variable &lt;code&gt;SECRET_SAUCE&lt;/code&gt; drawn from a secret named &lt;code&gt;secret-sauce&lt;/code&gt; under the key &lt;code&gt;SECRET_SAUCE&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flask
  template:
    metadata:
      labels:
        app: flask
    spec:
      containers:
        - name: webapp
          image: app
          imagePullPolicy: Never
          env:
            - name: SECRET_SAUCE
              valueFrom:
                secretKeyRef:
                  name: secret-sauce
                  key: SECRET_SAUCE
          ports:
            - containerPort: 5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the updated &lt;code&gt;Deployment&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f deployment.yaml
deployment.apps/app configured
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The changed &lt;code&gt;Deployment&lt;/code&gt; manifest will recreate any necessary pods, so invoke a new forwarded port once the pods have restarted to forward requests to the new containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl port-forward deployment/app 5000:5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, Issue an HTTP request to the running container to see the injected Doppler secret in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:5000
The secret sauce is: tzatziki!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the content of this secret differs from the one we saw in our local development environment. The &lt;code&gt;--config prd&lt;/code&gt; flag to the &lt;code&gt;doppler&lt;/code&gt; command loaded a token with rights to the &lt;code&gt;prd&lt;/code&gt; configuration in Doppler, which injects the correct secret for the configuration that the Doppler token has been scoped to.&lt;/p&gt;

&lt;p&gt;Congratulations! You've successfully:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installed the External Secrets Operator into your Kubernetes cluster&lt;/li&gt;
&lt;li&gt;Managed an application secret with Doppler&lt;/li&gt;
&lt;li&gt;Connected Doppler with the External Secrets Operator&lt;/li&gt;
&lt;li&gt;Used a Doppler project secret within a Kubernetes Deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;There's even more you can do with the External Secrets Operator and Doppler, so if you'd like to learn more, dive into the &lt;a href="https://external-secrets.io/latest/provider/doppler/"&gt;documentation&lt;/a&gt; to learn how to use features like JSON processing, filtering, and more.&lt;/p&gt;

&lt;p&gt;If you're actively using Kubernetes secrets stored in &lt;code&gt;etcd&lt;/code&gt; today, you should also &lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/"&gt;configure encryption at rest&lt;/a&gt; so that your secrets are secure no matter where they're stored. Whether you load them with &lt;code&gt;kubectl&lt;/code&gt; or the External Secrets Operator, configuring encryption at rest is still an important step to address every step of your secret management lifecycle.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Crash course in Web3 Application Development with Python</title>
      <dc:creator>Tyler Langlois</dc:creator>
      <pubDate>Tue, 31 May 2022 13:00:00 +0000</pubDate>
      <link>https://forem.com/doppler/crash-course-in-web3-application-development-with-python-1a1e</link>
      <guid>https://forem.com/doppler/crash-course-in-web3-application-development-with-python-1a1e</guid>
      <description>&lt;p&gt;In the world of cryptocurrency, private keys are king. Mathematical mechanics treat correctly signed transactions as valid regardless of intent, which makes account keys and passphrases a particularly lucrative target for malicious actors. While &lt;a href="https://blog.doppler.com/siloed-secrets-and-security-theatre-why-we-need-secretops"&gt;end-user best practices for securing keys&lt;/a&gt; tend to be plentiful, the development side of blockchain work takes place amid a sea of API tokens, key files, and service credentials that can &lt;a href="https://blog.doppler.com/secrets-sprawl-is-hurting-your-productivity-heres-how-to-fix-it"&gt;sprawl out of control&lt;/a&gt; if not managed correctly.&lt;/p&gt;

&lt;p&gt;Ensuring that these sensitive values remain secure is critical and &lt;a href="https://blog.doppler.com/the-triumph-and-tragedy-of-env-files"&gt;outdated solutions such as &lt;code&gt;.env&lt;/code&gt;&lt;/a&gt; files are no longer sufficient.&lt;/p&gt;

&lt;p&gt;This tutorial will start from the basics of interacting with blockchain APIs from joining as a peer upwards. There are numerous third-party services and APIs that sit atop various blockchains, but establishing secure management practices for primitives such as private keys is fundamental.&lt;/p&gt;

&lt;p&gt;No prior experience interacting with blockchain or web3 services is assumed, and we'll use a &lt;a href="https://en.wikipedia.org/wiki/Testnet"&gt;testnet&lt;/a&gt; in order to limit the potential exposure of sensitive information. &lt;a href="https://www.doppler.com/"&gt;Doppler&lt;/a&gt; will be used to store and retrieve credentials associated with private key material, which is a secure and convenient way to manage secrets without the risks of storing them on disk in unencrypted text files.&lt;/p&gt;

&lt;p&gt;Before downloading any programs or generating account keys, there are a few concepts to establish heading into the unique paradigms that accompany working with web3 networks.&lt;/p&gt;

&lt;p&gt;While plenty of unique blockchains and products abound in the web3 space, this guide will focus on the &lt;a href="https://en.wikipedia.org/wiki/Ethereum"&gt;Ethereum&lt;/a&gt; blockchain, which is one of the more commonly used networks. Like most cryptocurrency blockchains, Ethereum operates in a decentralized way with a vast network of computers that can be interacted with as a peer. However, any sort of operation that requires some proof of ownership, e.g. signing a transaction, does require the authoritative stamp of a private key.&lt;/p&gt;

&lt;p&gt;This is the core of how the network operates, which makes the method of communication and management of privileged information a chief concern.&lt;/p&gt;

&lt;p&gt;This tutorial will follow a basic outline to work directly with the Ethereum blockchain and its API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connecting to the testnet&lt;/li&gt;
&lt;li&gt;Generating and securing public keys&lt;/li&gt;
&lt;li&gt;Receiving tokens&lt;/li&gt;
&lt;li&gt;Sending tokens securely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's begin!&lt;/p&gt;

&lt;h2&gt;
  
  
  A Chain Primer
&lt;/h2&gt;

&lt;p&gt;When choosing how to connect to the Ethereum blockchain, there are two general approaches, each with distinct advantages and disadvantages.&lt;/p&gt;

&lt;p&gt;The first is by connecting to a third-party API that serves as a frontend to low-level blockchain network protocols. Services like &lt;a href="https://infura.io/"&gt;Infura&lt;/a&gt; offer a web-based JSON RPC API, which is widely compatible with a range of libraries and languages and allows developers to interact with the blockchain without downloading the entire ledger, which can take up significant compute resources and disk space (around 500GB at the time of this writing).&lt;/p&gt;

&lt;p&gt;Using a third-party API means that your code can run from a variety of environments without being tethered to a running node and the accompanying resource requirements that are necessary. The downside to this approach is reliance upon a third party when one of the core advantages of blockchain technology is &lt;em&gt;decentralisation&lt;/em&gt;. Routing communication with the aid of an intermediary party is convenient, but means that clients must trust the provider and are subject to the inherent properties of using a hosted API instead of communicating directly via peer protocols (such as availability and uptime). These tradeoffs are often the right choice, but are tradeoffs nonetheless.&lt;/p&gt;

&lt;p&gt;The second approach is to run a native node to communicate to the chosen blockchain directly. As previously mentioned, there are significant computational costs involved, but this means that the client speaks directly to the chosen peer network which brings with it benefits like smaller risk exposure, high availability of the decentralised network, and the ability to self-validate the ledger.&lt;/p&gt;

&lt;p&gt;There are additional considerations to take into account when operating a dedicated node, such as choosing whether to download the &lt;em&gt;entire&lt;/em&gt; ledger during the initial loading process or instead electing a more lightweight method that incurs a smaller disk usage cost.&lt;/p&gt;

&lt;p&gt;This guide will opt for the self-hosted node technique, though in practice, either approach is a reasonable choice.&lt;/p&gt;

&lt;p&gt;Finally, a node operator must select which network to connect to when initialising their connection.&lt;/p&gt;

&lt;p&gt;Normally, users will choose to connect to the live, "production" chain when interacting with a public ledger, but during local development and testing, a testnet is a better choice. In addition to less traffic (resulting in smaller ledgers and transaction costs), acquiring tokens to send and receive is usually free and does not require any initial funds. This is a significant advantage when sending and receiving tokens without risk of making mistakes that could incur significant consequences.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Steps
&lt;/h2&gt;

&lt;p&gt;We'll use &lt;a href="https://geth.ethereum.org/"&gt;geth&lt;/a&gt; (Go Ethereum) to connect to the Ethereum network, which is a golang implementation that can function not only as a client but a fully featured node as well.&lt;/p&gt;

&lt;p&gt;First, follow the &lt;a href="https://geth.ethereum.org/docs/install-and-build/installing-geth"&gt;instructions for installing geth&lt;/a&gt; for your operating system. Once installed, the &lt;code&gt;geth&lt;/code&gt; command should be available from the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;geth version
Geth
Version: 1.10.17-stable
Architecture: amd64
Go Version: go1.16.13
Operating System: linux
GOPATH=
GOROOT=/nix/store/j1x3cy8g2cqcr54rg98gw0mdc28jlyc8-go-1.16.13/share/go

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command-line flags passed to the geth CLI dictate which network it will connect to. There are &lt;a href="https://ethereum.org/en/developers/docs/networks/#testnets"&gt;a number of testnets within the Ethereum network&lt;/a&gt; to choose from, and this guide will use the Goerli proof-of-authority network as its newer than some of the others, and is not coupled with the computationally-expensive proof-of-work networks.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--syncmode&lt;/code&gt; flag controls the method that &lt;code&gt;geth&lt;/code&gt; will use when downloading the historical ledger of the blockchain. On one end of the extreme, the &lt;code&gt;full&lt;/code&gt; method will download the entirety of the blockchain ledger which includes all the relevant transactional data. On the other, the &lt;code&gt;light&lt;/code&gt; method will only fetch recent block headers and retrieve other information on-demand. When communicating with the production Ethereum network, the &lt;code&gt;full&lt;/code&gt; method offers the most comprehensive assurance that the local copy of blockchain data is valid and legitimate. However, in this exploratory case on a testnet, the &lt;code&gt;light&lt;/code&gt; method is sufficient.&lt;/p&gt;

&lt;p&gt;Begin the &lt;code&gt;geth&lt;/code&gt; process in a background terminal on your machine. The initial syncing process will take time, but using the &lt;code&gt;light&lt;/code&gt; method on the &lt;code&gt;goerli&lt;/code&gt; testnet will not use excessive space (at the time of this writing, the entirety of the chain requires about 500MB of disk space). The following command will store the Goerli chain data in the &lt;code&gt;~/.goerli&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;geth --syncmode light --datadir ~/.goerli --goerli
INFO [04-05|15:54:49.916] Starting Geth on Goerli testnet...
...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After some time, the daemon will stop importing historical blocks and the latest blocks will be available.&lt;/p&gt;

&lt;p&gt;The logging output from &lt;code&gt;geth&lt;/code&gt; will include the &lt;code&gt;age&lt;/code&gt; of a block when performing initial synchronisation. When you see blocks being imported with output such as &lt;code&gt;age=4m04w1d&lt;/code&gt;, this indicates old blocks being retrieved to construct the local chain. Once older blocks stop appearing, this indicates that the initial synchronisation is complete.&lt;/p&gt;

&lt;p&gt;You can continue with the rest of this guide while the blockchain synchronises; full synchronisation will only be necessary once we reach the portion that covers transactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accounts and Keys
&lt;/h2&gt;

&lt;p&gt;At the beginning of this guide, we spoke at length about the importance of keys when interacting with the blockchain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Public-key_cryptography"&gt;Public-key cryptography&lt;/a&gt; forms the backbone of the cryptographic methods for forming and authenticating transactions on public ledgers. Private keys prove ownership of public addresses and sign transactions to send tokens to other public addresses.&lt;/p&gt;

&lt;p&gt;While high-level, user-facing cryptocurrency applications may leverage account information for wallets in the form of traditional username/password combinations, the core values that comprise an "account" on a blockchain like Ethereum is a cryptographic key - tokens belong to an addressed coupled to a private key. The geth CLI includes utilities to generate keys, which it calls an &lt;strong&gt;account&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To begin, create a new account. Remember that this "account" is really a locally encrypted file and not an account that can be "logged into" from another machine - if you are using an account tied to a production blockchain, it's critical to ensure that this account is secured by a strong passphrase backed up regularly.&lt;/p&gt;

&lt;p&gt;In our case, the local account and keypair will be associated with a testnet, but we'll still use best practices for managing the passphrase by storing it in encrypted secrets store (Doppler) and treat the account as sensitive. Because the running &lt;code&gt;geth&lt;/code&gt; process is active, we'll connect to the running daemon via &lt;code&gt;attach&lt;/code&gt; instead of using the &lt;code&gt;geth account&lt;/code&gt; subcommand.&lt;/p&gt;

&lt;p&gt;Enter the &lt;code&gt;geth&lt;/code&gt; console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;geth --datadir ~/.goerli attach

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll be greeted by the command prompt for &lt;code&gt;geth&lt;/code&gt; javascript commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Welcome to the Geth JavaScript console!

instance: Geth/v1.10.17-stable/linux-amd64/go1.16.13
at block: 6664849 (Tue Apr 05 2022 17:34:43 GMT-0600 (MDT))
datadir: /home/yourname/.goerli
modules: admin:1.0 clique:1.0 debug:1.0 eth:1.0 les:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 vflux:1.0 web3:1.0

To exit, press ctrl-d or type exit
&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create a new account, run the following command where you'll be asked to enter a passphrase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;personal.newAccount()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After following the prompts, &lt;code&gt;geth&lt;/code&gt; will create a keypair within the &lt;code&gt;~/.goerli/keystore/&lt;/code&gt; directory. You can view the public address of this account at any time by using the following command from the &lt;code&gt;geth&lt;/code&gt; console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;personal.listAccounts

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, your local machine will have a light copy of the Ethereum Goerli testnet blockchain and a keypair ready to send and receive tokens. Let's begin working with transactions!&lt;/p&gt;

&lt;h2&gt;
  
  
  Interacting with the Blockchain
&lt;/h2&gt;

&lt;p&gt;A simple task to confirm the functionality of this local testnet setup is to receive currency. Unlike currency on the live, production blockchain, currency on a testnet is often given away freely to permit developers to test and iterate on projects and products.&lt;/p&gt;

&lt;p&gt;Providers for free currency - often called "faucets" - may sometimes be unavailable or lacking sufficient funds to distribute tokens freely. At the time of this writing, the faucet mentioned here is functional and has sufficient funds to distribute them to anyone who requests them, but if you encounter problems requesting funds at a later date than when this tutorial was written, you may also seek out alternate sources (remember that they must be operating on the Goerli Ethernet testnet).&lt;/p&gt;

&lt;p&gt;Well be using the &lt;a href="https://goerlifaucet.com/"&gt;Goerli Faucet&lt;/a&gt; to acquire initial funds to begin experimenting with the blockchain.&lt;/p&gt;

&lt;p&gt;From the &lt;code&gt;geth&lt;/code&gt; console, find your public address using &lt;code&gt;listAccounts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;personal.listAccounts
["0x..."]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the address, navigate to the &lt;a href="https://goerlifaucet.com/"&gt;Goerli Faucet&lt;/a&gt;, paste your address into the Wallet Address field, then click &lt;strong&gt;Send Me ETH&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---Mwlk3Ox--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1653001171755/c5pk5BGRt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---Mwlk3Ox--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1653001171755/c5pk5BGRt.png" alt="Goerli Testnet Faucet" width="880" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Blocks are minted frequently on this chain, so it's time to check your balance! We'll use the &lt;a href="https://web3py.readthedocs.io/en/stable/index.html"&gt;Web3&lt;/a&gt; Python library to interact with the local node.&lt;/p&gt;

&lt;p&gt;This guide assumes that you have Python 3 installed on your local machine. Weve provided a &lt;a href="https://github.com/DopplerUniversity/python-web3"&gt;repository with sample code&lt;/a&gt; as a quick start to getting up to speed with how to use the Web3 library.&lt;/p&gt;

&lt;p&gt;Clone the GitHub repository then enter the repository directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/DopplerUniversity/python-web3
cd python-web3

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a Python virtual environment and install the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to open &lt;code&gt;web3-app.py&lt;/code&gt; and take a look! The &lt;a href="https://pypi.org/project/web3/"&gt;Python web3&lt;/a&gt; library makes accessing blockchain information fairly straightforward, so this example code should be a good place to start if you want to experiment later.&lt;/p&gt;

&lt;p&gt;Let's verify the script is working by fetching the timestamp of the latest block on the chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python web3-app.py latest-block

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see a timestamp that is within 30 seconds or so, congratulations! You've successfully interacted with your local instance of the testnet blockchain. The next task is to check the balance of the address that your faucet tokens were sent to.&lt;/p&gt;

&lt;p&gt;First, confirm that Python is able to see the local account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python web3-app.py accounts

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your account number should match the address that you previously found within the &lt;code&gt;geth&lt;/code&gt; console using &lt;code&gt;personal.listAccounts&lt;/code&gt;. Finally, check the account balance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python web3-app.py balance

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The account balance for the address entered in the Ethereum faucet site should be &lt;code&gt;0.05&lt;/code&gt; ETH. You've checked your account balance from the python &lt;code&gt;web3&lt;/code&gt; library. Well done!&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending ETH
&lt;/h2&gt;

&lt;p&gt;Until now we've only interacted with the local blockchain with APIs that do not require private account keys. In order to finish this experiment and successfully sign a transaction with your account, we'll practice by sending an amount of ETH back to the Goerli faucet. Doing so will help demonstrate the process as well as replenish funds to future developers on the blockchain!&lt;/p&gt;

&lt;p&gt;To send ETH, well use the &lt;code&gt;send_transaction&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;web3.geth.personal.send_transaction(self, transaction, passphrase)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember when we created our local Geth account and provided the passphrase?&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;passphrase&lt;/em&gt; is required here to unlock the private key and sign the transaction in order to validate it as a legitimate transfer of funds out of our account. However, entering a passphrase into a REPL or a shell is a security concern: most REPL and shell histories (like bash or the python interpreter) retain commands that are entered, so it's wise to avoid entering a passphrase manually in plaintext.&lt;/p&gt;

&lt;p&gt;What other options exist? One approach is to read secret values - whether it be a passphrase, API key, or otherwise from a file on disk such as &lt;code&gt;.env&lt;/code&gt; or JS file but this is a dangerous option as well explain.&lt;/p&gt;

&lt;p&gt;Storing secrets in plaintext files is a huge security nightmare are as they can be read by other user processes, and risk being committed during work with tools like git if a developer makes a mistake such as &lt;a href="https://twitter.com/nateliason/status/1392086702794149894"&gt;Nat Eliason did when he lost $30,000&lt;/a&gt; by accidentally pushing a file containing his passphrase to GitHub.&lt;/p&gt;

&lt;p&gt;Reading the value from an environment variable is a good idea, but that begs the question of how the environment variable containing the passphrase will be securely populated.&lt;/p&gt;

&lt;p&gt;This is where a SecretOps platform such as &lt;a href="https://www.doppler.com/"&gt;Doppler&lt;/a&gt; can help by using the Doppler CLI to inject secrets as environment variables into an application process. This allows an environment variable to be populated with the passphrase securely without the risks of unencrypted local file storage.&lt;/p&gt;

&lt;p&gt;To begin, first &lt;a href="https://dashboard.doppler.com/register"&gt;sign up&lt;/a&gt; for a Doppler account. The sign up process will walk through a few helpful tips to get started, and once your account has been configured, proceed to &lt;a href="https://docs.doppler.com/docs/install-cli"&gt;install the Doppler CLI&lt;/a&gt;, then authenticate your machine by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;doppler login

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new project called &lt;strong&gt;python-web3&lt;/strong&gt; which will hold the secrets for this project and keep things organised as well as within their own environment scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;doppler projects create python-web3
doppler setup --project python-web3 --config dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure that you run &lt;code&gt;doppler setup&lt;/code&gt; in the python-web3 directory as the Doppler CLI scopes secrets access to specific directories. Eventually you should have a setup similar to the one below: with your project directory coupled to the &lt;code&gt;python-web3&lt;/code&gt; project in Doppler.&lt;/p&gt;

&lt;p&gt;Run the following command to check you can access secrets from the python-web3 directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;doppler secrets

 ID NAME DESCRIPTION CREATED AT               

 python-web3 python-web3 2022-05-24T23:40:34.955Z 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to store the keychain passphrase in Doppler where it can be retrieved by the &lt;code&gt;doppler&lt;/code&gt; CLI.&lt;/p&gt;

&lt;p&gt;Open the &lt;a href="https://dashboard.doppler.com/workplace/projects/python-web3/configs/dev"&gt;python-web3 Doppler Project&lt;/a&gt; and create a &lt;code&gt;ETH_PASSPHRASE&lt;/code&gt; with your passphrase value, then click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IT_KQduu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1653409515944/nw2Wac9uL.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IT_KQduu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1653409515944/nw2Wac9uL.png" alt="Doppler configuration dashboard" width="880" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Heading back to the terminal, can verify Doppler saved your passphrase successfully by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;doppler secrets get ETH_PASSPHRASE

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the passphrase managed by Doppler, we can now run the python script with secrets populated by the &lt;code&gt;doppler run&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;You may inspect the accompanying python code from the cloned repository, but the key lines are those that &lt;a href="https://github.com/DopplerUniversity/python-web3/blob/main/web3-app.py#L30"&gt;retrieve your passphrase&lt;/a&gt; from the &lt;code&gt;ETH_PASSPHRASE&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;When you invoke the &lt;code&gt;doppler run&lt;/code&gt; command, Doppler will set the &lt;code&gt;ETH_PASSPHRASE&lt;/code&gt; environment variable for python to use and sign the transaction with the wallet information from the unlocked key. Although the noted address is that of the faucet you originally received your balance from, you may choose an arbitrary amount to send with your command (as long as you have sufficient funds!).&lt;/p&gt;

&lt;p&gt;You can find a random account to send funds to from the &lt;a href="https://goerli.etherscan.io/accounts"&gt;Goerli top accounts page&lt;/a&gt;. Copy one of the to addresses (starting with 0x) and replace &lt;code&gt;{ADDRESS}&lt;/code&gt; in the command below to begin the funds transfer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;doppler run -- python web3-app.py send {ADDRESS} 0.01

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transaction once complete will return a unique transaction hash like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HexBytes('0x0d8c2b6924a88cda73c73275051245db7a7e698f419a9d27b8b185dda16a8436')

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your transaction has been submitted to the blockchain! At this point the running &lt;code&gt;geth&lt;/code&gt; light node will broadcast this transaction and the transfer of funds will propagate through the network. You may use a few approaches to view the transaction details.&lt;/p&gt;

&lt;p&gt;The provided python script supports a command to introspect an arbitrary transaction ID for example, the following command will display the transaction details of the aforementioned transaction ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python web3-app.py get-txn 0x0d8c2b6924a88cda73c73275051245db7a7e698f419a9d27b8b185dda16a8436

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to viewing details from a local client, using another method to introspect the public ledger is a good idea in order to confirm that the transaction is visible from any client.&lt;/p&gt;

&lt;p&gt;For example, you can either use a generally-available web-based block explorer to view transactions associated with a specific address (replace the given hash with yours that is under the variable in your python repl as &lt;code&gt;my_account&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://goerli.etherscan.io/address/0x858Eb06Bd4dc5BE36Dc5025483a316E1630b35e9"&gt;https://goerli.etherscan.io/address/0x858Eb06Bd4dc5BE36Dc5025483a316E1630b35e9&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you may alternatively view the transaction directly by entering your transaction hash into a URL like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://goerli.etherscan.io/tx/0x0d8c2b6924a88cda73c73275051245db7a7e698f419a9d27b8b185dda16a8436"&gt;https://goerli.etherscan.io/tx/0x0d8c2b6924a88cda73c73275051245db7a7e698f419a9d27b8b185dda16a8436&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In either case you should be able to see the transaction data including the amount and associated gas price.&lt;/p&gt;

&lt;p&gt;Congratulations! You just created a transaction on an Ethereum blockchain!&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Considerations
&lt;/h2&gt;

&lt;p&gt;This guide has covered one of the most basic operations when working with a blockchain - signing and broadcasting a transaction - using Doppler to manage your passphrase securely so crypto keys and passphrases arent inadvertently exposed along with any other sensitive account credentials.&lt;/p&gt;

&lt;p&gt;Recall that in this tutorial, we generated a keychain using the &lt;code&gt;geth&lt;/code&gt; CLI so the associated public and private key exist only on the local machine.&lt;/p&gt;

&lt;p&gt;To write code that could potentially run on any host with a keychain stored remotely, you could elect to store key material in Doppler and instantiate a local keychain based upon the retrieval of that information from a similar Doppler secret.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;web3&lt;/code&gt; library provides the &lt;code&gt;web3.geth.personal.import_raw_key&lt;/code&gt; method which accepts a private key and passphrase so that your transaction operations can occur on any machine with a properly setup Doppler environment. The local blockchain can be used for more experiments by virtue of the flexibility of the testnet environment, so you can continue to receive currency from a Goerli testnet faucet and send funds to other addresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;For additional information, these resources provide more documentation and information about the libraries and tools used in this guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web3py.readthedocs.io/en/stable/index.html"&gt;Web3.py documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ethereum.org/en/developers/docs/transactions/"&gt;Transactions | ethereum.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ethereum.org/en/developers/docs/networks/"&gt;Networks | ethereum.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://goerli.net/"&gt;Goerli Testnet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.doppler.com/docs/getting-started"&gt;Doppler SecretOps Platform | Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
