Dapr is an event-driven, portable runtime for building microservices on cloud and edge.
Dapr supports the fundamental features you’ll need such as: service invocation, state management, publish/subscribe messaging and since version 0.5.0 the ability to read from secret stores!
This post will show you to read kubernetes secrets using Dapr and .NET Core:
Prerequistes
- .Net Core SDK 3.1
- Dapr CLI
- Dapr DotNet SDK
- Docker
- A working kubernetes cluster
Create an .NET Core project and add dependencies
Open the command line and type:
1dotnet new web -o dapr.k8s.secrets
2
3cd dapr.k8s.secrets
4
5dotnet add package Dapr.Client -v 0.5.0-preview02
Update Startup.cs
Update Startup.cs with the following contents in order to expose a secret endpoint and use Dapr to fetch a kubernetes secret:
1namespace dapr.k8s.secrets
2{
3 using System.Text.Json;
4 using System.Threading.Tasks;
5 using Microsoft.AspNetCore.Builder;
6 using Microsoft.AspNetCore.Hosting;
7 using Microsoft.AspNetCore.Http;
8 using Microsoft.Extensions.Configuration;
9 using Microsoft.Extensions.Hosting;
10 using Microsoft.Extensions.DependencyInjection;
11 using Dapr.Client;
12 using System;
13 using System.Collections.Generic;
14
15 public class Startup
16 {
17 // Dapr listens for requets on localhost
18 const string localhost = "127.0.0.1";
19
20 // Get the Dapr gRPC port
21 static string daprPort => Environment.GetEnvironmentVariable("DAPR_GRPC_PORT") ?? "50001";
22
23 public Startup(IConfiguration configuration)
24 {
25 Configuration = configuration;
26 }
27
28 public IConfiguration Configuration { get; }
29
30 public void ConfigureServices(IServiceCollection services)
31 {
32 // Create Dapr Client
33 var client = new DaprClientBuilder()
34 .UseEndpoint($"https://{localhost}:{daprPort}")
35 .Build();
36
37 // Add the DaprClient to DI.
38 services.AddSingleton<DaprClient>(client);
39 }
40
41 public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DaprClient client)
42 {
43 if (env.IsDevelopment())
44 {
45 app.UseDeveloperExceptionPage();
46 }
47
48 app.UseRouting();
49
50 app.UseEndpoints(endpoints =>
51 {
52 // Add the secrets route
53 endpoints.MapGet("secret", Secret);
54 });
55
56 async Task Secret(HttpContext context)
57 {
58 // Get the secret from kubernetes
59 var secretValues = await client.GetSecretAsync(
60 "kubernetes", // Name of the Dapr Secret Store
61 "super-secret", // Name of the k8s secret
62 new Dictionary<string, string>() { { "namespace", "default" } }); // Namespace where the k8s secret is deployed
63
64 // Get the secret value
65 var secretValue = secretValues["super-secret"];
66
67 context.Response.ContentType = "application/json";
68 await JsonSerializer.SerializeAsync(context.Response.Body, secretValue);
69 }
70 }
71 }
72}
Create a Dockerfile with the following contents:
1FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS builder
2WORKDIR /app
3
4# caches restore result by copying csproj file separately
5COPY *.csproj .
6RUN dotnet restore
7
8COPY . .
9RUN dotnet publish --output /app/ --configuration Release
10RUN sed -n 's:.*<AssemblyName>\(.*\)</AssemblyName>.*:\1:p' *.csproj > __assemblyname
11RUN if [ ! -s __assemblyname ]; then filename=$(ls *.csproj); echo ${filename%.*} > __assemblyname; fi
12
13# Stage 2
14FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
15WORKDIR /app
16COPY --from=builder /app .
17
18ENV PORT 80
19EXPOSE 80
20
21ENTRYPOINT dotnet $(cat /app/__assemblyname).dll
Build the Docker image and push it to a container registry
I’ll be pushing the container to Docker Hub:
1 docker build -t cmendibl3/dapr-k8s-secrets:1.0.0 .
2 docker push cmendibl3/dapr-k8s-secrets:1.0.0
Create manifest and deploy the application to kubernetes
Create a deployment.yaml with the following contents (remember to replace the image with your own values):
1---
2# ASP.NET Core Application
3apiVersion: apps/v1beta1
4kind: Deployment
5metadata:
6 name: dapr-k8s-secrets
7 namespace: default
8spec:
9 replicas: 1
10 template:
11 metadata:
12 labels:
13 app: dapr-k8s-secrets
14 aadpodidbinding: requires-vault
15 annotations:
16 dapr.io/enabled: "true"
17 dapr.io/id: "dapr-k8s-secrets"
18 dapr.io/port: "80"
19 spec:
20 containers:
21 - name: dapr-k8s-secrets
22 image: cmendibl3/dapr-k8s-secrets:1.0.0
23 ports:
24 - containerPort: 80
25 imagePullPolicy: Always
26---
27# Create a Kubernetes Secret
28apiVersion: v1
29kind: Secret
30metadata:
31 name: super-secret
32 namespace: default
33type: Opaque
34data:
35 super-secret: eW91ciBzdXBlciBzZWNyZXQK
36
37---
38# If RBAC is enabled in K8s, give the default service account access to read secrets in the default namespace
39apiVersion: rbac.authorization.k8s.io/v1
40kind: ClusterRoleBinding
41metadata:
42 name: dapr-secret-reader
43roleRef:
44 apiGroup: rbac.authorization.k8s.io
45 kind: ClusterRole
46 name: secret-reader
47subjects:
48 - kind: ServiceAccount
49 name: default
50 namespace: default
If you haven’t installed Dapr in your kuberntes cluster run:
1dapr init --kubernetes
Now deploy the application to kubernetes:
1kubectl apply -f ./deployment.yaml
Test the application
Get the pod name and execute a port forward to test the API
1$pod = kubectl get po --selector=app=dapr-k8s-secrets -n default -o jsonpath='{.items[*].metadata.name}'
2kubectl port-forward $pod 80:80
Run the following command in other terminal:
1curl http://localhost/secret
If everything is working you should read:
1"your super secret"
Hope it helps!
Please find all code and files here, and learn more about Dapr and the Secret API here
Comments