mirror of https://github.com/dapr/quickstarts.git
Merge pull request #850 from ItalyPaleAle/crypto-go
Cryptography quickstart for Go
This commit is contained in:
commit
7d140fee39
25
README.md
25
README.md
|
@ -7,30 +7,33 @@
|
|||
If you are new to Dapr and haven't done so already, it is recommended you go through the Dapr [Getting Started](https://docs.dapr.io/getting-started/install-dapr-cli/) instructions.
|
||||
|
||||
### Quickstarts
|
||||
Pick a building block API (for example, pub-sub, state management) and rapidly try it out in your favorite language SDK (recommended), or via HTTP. Visit the [Dapr Docs Quickstarts Guide](https://docs.dapr.io/getting-started/quickstarts/) for a comprehensive walkthrough of each example.
|
||||
|
||||
Pick a building block API (for example, PubSub, state management, etc) and rapidly try it out in your favorite language SDK (recommended), or via HTTP. Visit the [Dapr Docs Quickstarts Guide](https://docs.dapr.io/getting-started/quickstarts/) for a comprehensive walkthrough of each example.
|
||||
|
||||
| Dapr Quickstart | Description |
|
||||
|:--------------------:|:--------------------:|
|
||||
|:--------:|:--------:|
|
||||
| [Publish and Subscribe](./pub_sub) | Asynchronous communication between two services using messaging |
|
||||
| [Service Invocation](./service_invocation) | Synchronous communication between two services using HTTP |
|
||||
| [Service Invocation](./service_invocation) | Synchronous communication between two services using HTTP |
|
||||
| [State Management](./state_management/) | Store a service's data as key/value pairs in supported state stores |
|
||||
| [Bindings](./bindings/) | Work with external systems using input bindings to respond to events and output bindings to call operations|
|
||||
| [Bindings](./bindings/) | Work with external systems using input bindings to respond to events and output bindings to call operations |
|
||||
| [Secrets Management](./secrets_management/) | Securely fetch secrets |
|
||||
| [Actors](./actors) | Create stateful, long running objects with identity |
|
||||
| [Configuration](./configuration) | Get configuration items as key/value pairs or subscribe to changes whenever a configuration item changes |
|
||||
| [Cryptography](./cryptography) | Perform cryptographic operations without exposing keys to your application |
|
||||
| [Resiliency](./resiliency) | Define and apply fault-tolerant policies (retries/back-offs, timeouts and circuit breakers) to your Dapr API requests |
|
||||
| [Workflow](./workflows) | Dapr Workflow enables you to create long running, fault-tolerant, stateful applications. |
|
||||
| [Workflow](./workflows) | Dapr Workflow enables you to create long running, fault-tolerant, stateful applications |
|
||||
|
||||
### Tutorials
|
||||
|
||||
Go deeper into a topic or scenario, oftentimes using building block APIs together to solve problems (for example, build a distributed calculator, build and deploy an app to Kubernetes).
|
||||
|
||||
| Tutorials | Description |
|
||||
|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [Hello-world](./tutorials/hello-world) | Demonstrates how to run Dapr locally. Highlights service invocation and state management. |
|
||||
| [Hello-kubernetes](./tutorials/hello-kubernetes) | Demonstrates how to run Dapr in Kubernetes. Highlights service invocation and state management. |
|
||||
| Tutorials | Description |
|
||||
|------|------|
|
||||
| [Hello-world](./tutorials/hello-world) | Demonstrates how to run Dapr locally. Highlights service invocation and state management. |
|
||||
| [Hello-kubernetes](./tutorials/hello-kubernetes) | Demonstrates how to run Dapr in Kubernetes. Highlights service invocation and state management. |
|
||||
| [Distributed-calculator](./tutorials/distributed-calculator) | Demonstrates a distributed calculator application that uses Dapr services to power a React web app. Highlights polyglot (multi-language) programming, service invocation and state management. |
|
||||
| [Pub-sub](./tutorials/pub-sub) | Demonstrates how to use Dapr to enable pub-sub applications. Uses Redis as a pub-sub component. |
|
||||
| [Bindings](./tutorials/bindings) | Demonstrates how to use Dapr to create input and output bindings to other components. Uses bindings to Kafka. |
|
||||
| [Pub-sub](./tutorials/pub-sub) | Demonstrates how to use Dapr to enable pub-sub applications. Uses Redis as a pub-sub component. |
|
||||
| [Bindings](./tutorials/bindings) | Demonstrates how to use Dapr to create input and output bindings to other components. Uses bindings to Kafka.|
|
||||
| [Observability](./tutorials/observability) | Demonstrates Dapr tracing capabilities. Uses Zipkin as a tracing component. |
|
||||
| [Secret Store](./tutorials/secretstore) | Demonstrates the use of Dapr Secrets API to access secret stores. |
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: localstorage
|
||||
spec:
|
||||
type: crypto.dapr.localstorage
|
||||
version: v1
|
||||
metadata:
|
||||
- name: path
|
||||
# Path is relative to the folder where the example is located
|
||||
value: ./keys
|
|
@ -0,0 +1,73 @@
|
|||
# Dapr cryptography (Dapr SDK)
|
||||
|
||||
In this quickstart, you'll create an application that encrypts, and then decrypts, data using the Dapr cryptography APIs (high-level). We will:
|
||||
|
||||
- Encrypt and then decrypt a short string, reading the result in-memory, in a Go byte slice
|
||||
- Encrypt and then decrypt a large file, storing the encrypted and decrypted data to files using streams
|
||||
|
||||
Visit the documentation to learn more about the [Cryptography building block](https://v1-11.docs.dapr.io/developing-applications/building-blocks/cryptography/) in Dapr.
|
||||
|
||||
> **Note:** This example uses the Dapr SDK. Using the Dapr SDK, which leverages gRPC internally, is **strongly** recommended when using the high-level cryptography APIs (to encrypt and decrypt messages).
|
||||
|
||||
This quickstart includes one application:
|
||||
|
||||
- Go application `crypto-quickstart`
|
||||
|
||||
### Run Go service with Dapr
|
||||
|
||||
> In order to run this sample, make sure that OpenSSL is available on your system.
|
||||
|
||||
1. Navigate into the folder with the source code:
|
||||
|
||||
<!-- STEP
|
||||
name: Navigate into folder
|
||||
expected_stdout_lines:
|
||||
expected_stderr_lines:
|
||||
-->
|
||||
|
||||
```bash
|
||||
cd ./crypto-quickstart
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
||||
2. This sample requires a private RSA key and a 256-bit symmetric (AES) key. We will generate them using OpenSSL:
|
||||
|
||||
<!-- STEP
|
||||
name: Generate keys
|
||||
working_dir: crypto-quickstart
|
||||
expected_stdout_lines:
|
||||
expected_stderr_lines:
|
||||
-->
|
||||
|
||||
```bash
|
||||
mkdir -p keys
|
||||
# Generate a private RSA key, 4096-bit keys
|
||||
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out keys/rsa-private-key.pem
|
||||
# Generate a 256-bit key for AES
|
||||
openssl rand -out keys/symmetric-key-256 32
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
||||
|
||||
3. Run the Go service app with Dapr:
|
||||
|
||||
<!-- STEP
|
||||
name: Run order-processor service
|
||||
working_dir: crypto-quickstart
|
||||
expected_stdout_lines:
|
||||
- '== APP == Encrypted the message, got 856 bytes'
|
||||
- '== APP == Decrypted the message, got 24 bytes'
|
||||
- '== APP == The secret is "passw0rd"'
|
||||
- '== APP == Wrote decrypted data to encrypted.out'
|
||||
- '== APP == Wrote decrypted data to decrypted.out.jpg'
|
||||
- "Exited App successfully"
|
||||
expected_stderr_lines:
|
||||
output_match_mode: substring
|
||||
-->
|
||||
|
||||
```bash
|
||||
dapr run --app-id crypto-quickstart --resources-path ../../../components/ -- go run .
|
||||
```
|
||||
|
||||
<!-- END_STEP -->
|
|
@ -0,0 +1,6 @@
|
|||
# Output files
|
||||
encrypted.out
|
||||
decrypted.out.jpg
|
||||
|
||||
# Generated keys
|
||||
keys/
|
|
@ -0,0 +1,162 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
dapr "github.com/dapr/go-sdk/client"
|
||||
)
|
||||
|
||||
const (
|
||||
// Name of the crypto component to use
|
||||
CryptoComponentName = "localstorage"
|
||||
// Name of the RSA private key to use
|
||||
RSAKeyName = "rsa-private-key.pem"
|
||||
// Name of the symmetric (AES) key to use
|
||||
SymmetricKeyName = "symmetric-key-256"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a new Dapr SDK client
|
||||
client, err := dapr.NewClient()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to initialize the Dapr client: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Step 1: encrypt a string using the RSA key, then decrypt it and show the output in the terminal
|
||||
encryptDecryptString(client)
|
||||
|
||||
// Step 2: encrypt a large file and then decrypt it, using the AES key
|
||||
encryptDecryptFile(client)
|
||||
}
|
||||
|
||||
func encryptDecryptString(client dapr.Client) {
|
||||
const message = `The secret is "passw0rd"`
|
||||
|
||||
// Encrypt the message
|
||||
encStream, err := client.Encrypt(context.Background(),
|
||||
strings.NewReader(message),
|
||||
dapr.EncryptOptions{
|
||||
ComponentName: CryptoComponentName,
|
||||
// Name of the key to use
|
||||
// Since this is a RSA key, we specify that as key wrapping algorithm
|
||||
KeyName: RSAKeyName,
|
||||
KeyWrapAlgorithm: "RSA",
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to encrypt the message: %v", err)
|
||||
}
|
||||
|
||||
// The method returns a readable stream, which we read in full in memory
|
||||
encBytes, err := io.ReadAll(encStream)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read the stream for the encrypted message: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Encrypted the message, got %d bytes\n", len(encBytes))
|
||||
|
||||
// Now, decrypt the encrypted data
|
||||
decStream, err := client.Decrypt(context.Background(),
|
||||
bytes.NewReader(encBytes),
|
||||
dapr.DecryptOptions{
|
||||
// We just need to pass the name of the component
|
||||
ComponentName: CryptoComponentName,
|
||||
// Passing the name of the key is optional
|
||||
KeyName: RSAKeyName,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to decrypt the message: %v", err)
|
||||
}
|
||||
|
||||
// The method returns a readable stream, which we read in full in memory
|
||||
decBytes, err := io.ReadAll(decStream)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read the stream for the decrypted message: %v", err)
|
||||
}
|
||||
|
||||
// Print the message on the console
|
||||
fmt.Printf("Decrypted the message, got %d bytes\n", len(decBytes))
|
||||
fmt.Println(string(decBytes))
|
||||
}
|
||||
|
||||
func encryptDecryptFile(client dapr.Client) {
|
||||
const fileName = "liuguangxi-66ouBTTs_x0-unsplash.jpg"
|
||||
|
||||
// Get a readable stream to the input file
|
||||
plaintextF, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open plaintext file: %v", err)
|
||||
}
|
||||
defer plaintextF.Close()
|
||||
|
||||
// Encrypt the file
|
||||
encStream, err := client.Encrypt(context.Background(),
|
||||
plaintextF,
|
||||
dapr.EncryptOptions{
|
||||
ComponentName: CryptoComponentName,
|
||||
// Name of the key to use
|
||||
// Since this is a symmetric key, we specify AES as key wrapping algorithm
|
||||
KeyName: SymmetricKeyName,
|
||||
KeyWrapAlgorithm: "AES",
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to encrypt the file: %v", err)
|
||||
}
|
||||
|
||||
// Write the encrypted data to a file "encrypted.out"
|
||||
encryptedF, err := os.Create("encrypted.out")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open destination file: %v", err)
|
||||
}
|
||||
_, err = io.Copy(encryptedF, encStream)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write encrypted stream to file: %v", err)
|
||||
}
|
||||
encryptedF.Close()
|
||||
|
||||
fmt.Println("Wrote decrypted data to encrypted.out")
|
||||
|
||||
// Now, decrypt the encrypted data
|
||||
// First, open the file "encrypted.out" again, this time for reading
|
||||
encryptedF, err = os.Open("encrypted.out")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open encrypted file: %v", err)
|
||||
}
|
||||
defer encryptedF.Close()
|
||||
|
||||
// Now, decrypt the encrypted data
|
||||
decStream, err := client.Decrypt(context.Background(),
|
||||
encryptedF,
|
||||
dapr.DecryptOptions{
|
||||
// We just need to pass the name of the component
|
||||
ComponentName: CryptoComponentName,
|
||||
// Passing the name of the key is optional
|
||||
KeyName: SymmetricKeyName,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to decrypt the file: %v", err)
|
||||
}
|
||||
|
||||
// Write the decrypted data to a file "decrypted.out.jpg"
|
||||
decryptedF, err := os.Create("decrypted.out.jpg")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open destination file: %v", err)
|
||||
}
|
||||
_, err = io.Copy(decryptedF, decStream)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write decrypted stream to file: %v", err)
|
||||
}
|
||||
decryptedF.Close()
|
||||
|
||||
fmt.Println("Wrote decrypted data to decrypted.out.jpg")
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
module dapr_example
|
||||
|
||||
go 1.19
|
||||
|
||||
require github.com/dapr/go-sdk v1.6.1-0.20230526171131-942dcb8512fb
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
google.golang.org/grpc v1.55.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
|
@ -0,0 +1,39 @@
|
|||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/dapr/go-sdk v1.6.1-0.20230526171131-942dcb8512fb h1:6KSPlYMDOAeJkGX0vYNqJ1WggJJnpBH5WjgNs3wZJbs=
|
||||
github.com/dapr/go-sdk v1.6.1-0.20230526171131-942dcb8512fb/go.mod h1:MBcTKXg8PmBc8A968tVWQg1Xt+DZtmeVR6zVVVGcmeA=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
Binary file not shown.
After Width: | Height: | Size: 5.7 MiB |
|
@ -0,0 +1,9 @@
|
|||
include ../../../docker.mk
|
||||
include ../../../validate.mk
|
||||
|
||||
# Remove generated files
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -r crypto-quickstart/keys
|
||||
-rm crypto-quickstart/encrypted.out
|
||||
-rm crypto-quickstart/decrypted.out.jpg
|
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
# Dapr secrets management (HTTP Client)
|
||||
# Dapr secrets management (Dapr SDK)
|
||||
|
||||
In this quickstart, you'll create a microservice to demonstrate Dapr's secrets management API. The service fetches a secret from a secret store. See [Why secrets management](#why-secrets-management) to understand when to use this API.
|
||||
|
||||
|
|
Loading…
Reference in New Issue