chore: programatically generate the on-the-fly certificates for nats

This commit is contained in:
Manuel de la Peña
2025-03-19 14:21:55 +01:00
parent 823b9f9a6f
commit bc80cbb400
9 changed files with 61 additions and 164 deletions

View File

@@ -3,6 +3,7 @@ module github.com/gofiber/storage/nats
go 1.22
require (
github.com/mdelapenya/tlscert v0.1.0
github.com/nats-io/nats.go v1.37.0
github.com/stretchr/testify v1.9.0
github.com/testcontainers/testcontainers-go v0.35.0

View File

@@ -60,6 +60,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mdelapenya/tlscert v0.1.0 h1:YTpF579PYUX475eOL+6zyEO3ngLTOUWck78NBuJVXaM=
github.com/mdelapenya/tlscert v0.1.0/go.mod h1:wrbyM/DwbFCeCeqdPX/8c6hNOqQgbf0rUDErE1uD+64=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=

View File

@@ -1,15 +1,17 @@
package nats
import (
"bytes"
"context"
_ "embed"
"fmt"
"net"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/mdelapenya/tlscert"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"github.com/stretchr/testify/require"
@@ -25,23 +27,59 @@ const (
natsTLSPort = "4443/tcp"
)
var (
//go:embed testdata/nats-tls.conf
natsTLSConfig string
//go:embed testdata/nats-tls.conf
var natsTLSConfig string
//go:embed testdata/tls/ca.crt
caCrt string
// createTLSCerts creates a CA certificate, a client certificate and a nats certificate,
// storing them in the given temporary directory.
func createTLSCerts(t testing.TB) (*tlscert.Certificate, *tlscert.Certificate, *tlscert.Certificate) {
t.Helper()
//go:embed testdata/tls/redis.crt
redisCrt string
tmpDir := t.TempDir()
//go:embed testdata/tls/redis.key
redisKey string
)
// ips is the extra list of IPs to include in the certificates.
// It's used to allow the client and nats certificates to be used in the same host
// when the tests are run using a remote docker daemon.
ips := []net.IP{net.ParseIP("127.0.0.1")}
// Generate CA certificate
caCert := tlscert.SelfSignedFromRequest(tlscert.Request{
Host: "localhost",
IPAddresses: ips,
Name: "ca",
IsCA: true,
ParentDir: tmpDir,
})
require.NotNil(t, caCert)
// Generate client certificate
clientCert := tlscert.SelfSignedFromRequest(tlscert.Request{
Host: "localhost",
IPAddresses: ips,
Name: "client",
Parent: caCert,
ParentDir: tmpDir,
})
require.NotNil(t, clientCert)
// Generate nats certificate
natsCert := tlscert.SelfSignedFromRequest(tlscert.Request{
Host: "localhost",
IPAddresses: ips,
Name: "nats",
Parent: caCert,
ParentDir: tmpDir,
})
require.NotNil(t, natsCert)
return caCert, clientCert, natsCert
}
func newTestStore(t testing.TB) (*Storage, error) {
t.Helper()
ca, client, natsCert := createTLSCerts(t)
img := natsImage
if imgFromEnv := os.Getenv(natsImageEnvVar); imgFromEnv != "" {
img = imgFromEnv
@@ -60,18 +98,18 @@ func newTestStore(t testing.TB) (*Storage, error) {
ExposedPorts: []string{natsTLSPort},
Files: []testcontainers.ContainerFile{
{
Reader: strings.NewReader(caCrt),
Reader: bytes.NewReader(ca.Bytes),
ContainerFilePath: "/tls/ca.crt",
FileMode: 0o0644,
},
{
Reader: strings.NewReader(redisCrt),
ContainerFilePath: "/tls/redis.crt",
Reader: bytes.NewReader(natsCert.Bytes),
ContainerFilePath: "/tls/nats.crt",
FileMode: 0o0644,
},
{
Reader: strings.NewReader(redisKey),
ContainerFilePath: "/tls/redis.key",
Reader: bytes.NewReader(natsCert.KeyBytes),
ContainerFilePath: "/tls/nats.key",
FileMode: 0o0644,
},
},
@@ -96,13 +134,8 @@ func newTestStore(t testing.TB) (*Storage, error) {
NatsOptions: []nats.Option{
nats.MaxReconnects(2),
// Enable TLS with client certificate authentication
nats.ClientCert(
filepath.Join("testdata", "tls", "client.crt"),
filepath.Join("testdata", "tls", "client.key"),
),
nats.RootCAs(
filepath.Join("testdata", "tls", "ca.crt"),
),
nats.ClientCert(client.CertPath, client.KeyPath),
nats.RootCAs(ca.CertPath),
},
KeyValueConfig: jetstream.KeyValueConfig{
Bucket: "test",

View File

@@ -4,8 +4,8 @@ port: 4443
net: 0.0.0.0 # net interface
tls {
cert_file: "/tls/redis.crt"
key_file: "/tls/redis.key"
cert_file: "/tls/nats.crt"
key_file: "/tls/nats.key"
ca_file: "/tls/ca.crt"
timeout: 2
}

View File

@@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFSzCCAzOgAwIBAgIUfC9gg7i2wanN0MvFwCN2M7fLvwUwDQYJKoZIhvcNAQEL
BQAwNTETMBEGA1UECgwKUmVkaXMgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUg
QXV0aG9yaXR5MB4XDTI1MDMxOTEwMjQ0N1oXDTM1MDMxNzEwMjQ0N1owNTETMBEG
A1UECgwKUmVkaXMgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUgQXV0aG9yaXR5
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyfMcgNjn1u8P3yVnczlc
8U+vqk3APnQ84w4ywBs6i9SAhOCEZkg2FYpmSlcBVqHLrLl+9iA+2g3Hu3vOx4pC
GNewWCwR+JPU6Pt1+klu9HgS12BV9UuhsCmIsCa1Gr4vNJEVeWhJd21Eiqqmszy5
ji0SunOl0nQc9U+QrFvXLWmscvtWxbdy/3XV6anLGC9HkbcrWld9Cj8EGzDapiiX
GEiqWP/kltBSd8NT3bc3NROuXSXvRa1jnGZaulypD9iodjJ36xCIyWqxzoDAR5sp
1viMvltWJ91lhYJbohIJMVw8H6xDtuAvpeHdd20qm6i96hhTqoJEo6uhrnFzx6Pq
cKr/HVlaQEKk0ejRjHTktRIjGEx3+sl6u0Ntv2JHwqxSwgdmPAllu6A3fgIVCvyb
y/C7dayha+uGQIaUptMYmKDCCbZ2vc+IVI0bup8MLVDtA4PY9fX1y36PmYLJVpZS
LcUkLduiNN/XxXlvpf8rlJzaH49/E5G2z93wPQD5afIMdxsUofWOkYo95HpLQ2yS
iLOJnQQzDnBnFOn0b1nQD3Q7+nyduy0rbTgqobO1PwIszZWFelnnGfmfVnfkSd5H
tW5S027vgpZzXWHepdg7+vNBFR+ldp9/eMo+fVfpIz25gpkD5ex/c9IABwjFk5XJ
moXMh597Xzqd5IM4CWevMgECAwEAAaNTMFEwHQYDVR0OBBYEFIUuIA/xEEPAzymU
pXQPRVJ6fMiQMB8GA1UdIwQYMBaAFIUuIA/xEEPAzymUpXQPRVJ6fMiQMA8GA1Ud
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAFB8SOWUy7ciIR8QbZDis1dx
fmZeoW2Om2BJiYZV4uYMHg/k8FxHk7r0eFeXw5eNXSIt6VxS8pQ53q+iWJSc5n3J
PFY5KDgY0R5p4S5xv6FdCMBLdyN+64P/kx2EPS4kEZTb6MJHvyOD0w0HzCaqkYuq
7AJBYLzhBWj77tvKQnTP4p/21zk4S1lP/+dsesz8JvoOOV9Kw48mqhCsp55xPMh/
Ap2mYI9Ia7wnzDwaOXBCvu9KL+pUA1UkkclUqZoPkwUs6QaCmI+Z0TtA7053Cshe
lj/u8cxt7Ii91UNZ7gAxJhB5F79ObT/avMW/i/dI+LuycmaoYkISf3aYJX9xFuYC
6RLhmwanq7/pYEk2E2FdmsnLk0Z/gmzRwRnnLyr5aeoVX7si2ci0/j0ODGZGhjz3
zeLzbENjZDAgmeWy+tsmYT6UwkAz5gJde93E0WSvGfyjiPPTm9C3BduFjEYGdpVj
iAHS2aqEln78GYsXygs6VluN3f7T1GIGoBBN2o0JIgAvWTabuQROpFZaIl9gSHeZ
T0tNqA8kD6sKbSm0tkajK6b+dHUhDl3T9Pf6nv20zoTmcI1PyC1UnLyUqoGQGwNm
/8AKUbSK4hnDpPDI+F9LChH+VoBwibTInvHQlhqmINDNcjJcSopiBBYSi/r7GPTU
/gZhf9P3WSkf6OpzOkpc
-----END CERTIFICATE-----

View File

@@ -1,26 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEUDCCAjigAwIBAgIUegEAdDIUZsPJiiT5lRJ8Cx+PEPwwDQYJKoZIhvcNAQEL
BQAwNTETMBEGA1UECgwKUmVkaXMgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUg
QXV0aG9yaXR5MB4XDTI1MDMxOTEwMjQ0OFoXDTI2MDMxOTEwMjQ0OFowKzETMBEG
A1UECgwKUmVkaXMgVGVzdDEUMBIGA1UEAwwLQ2xpZW50LW9ubHkwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDl9fKTGnY/djZFQ9GTyaYL5/Gm2SILW1vt
JCtiaLSz+NFYZiDIay8f9xGhN4eG6eCCAI1rEjt6/kVPZsS6qqSKCbRzmvvQKHKx
e0s+F2F1VxV7ANyp3NFvLf7TJ/a961YPheALpIqC/XOrq/ZYob++RmS7UZZJTnnk
Hg+e0Ah0J/LNEepSirqGVhzoNkXBw8gAUZ1HePUd7ybvKe8S6MGOuNuQeGNd18Nc
KlzEl/LEVt1EIBsx5r3ZkRTbhCiYdFzreJGAhk4e/q+X/AfgCN17zYNxe/Pzlz/9
/ZD3YlDW8ZzwhTyDCihfe6cfCzun93JYyCpU3EYfooMvEvHQk9VLAgMBAAGjYjBg
MAsGA1UdDwQEAwIFoDARBglghkgBhvhCAQEEBAMCB4AwHQYDVR0OBBYEFOWONhi4
F+159BVyxoQGdz4nWz1oMB8GA1UdIwQYMBaAFIUuIA/xEEPAzymUpXQPRVJ6fMiQ
MA0GCSqGSIb3DQEBCwUAA4ICAQCXUIpag0Aekp5cXmVyvryjx5MkXKBKgLh2Hazv
X8joetjyVHbMUI6QMUScFt57R15FVB+CKl897ah4DgbtDEyAUtVqKtwHGBOpIj5l
ptNUtxZ770kCWpX1NdpS7iAOOhyQZeQG+vx18W2jNIpRR/2TAh5H9GOtv776eEE+
lwpEaDUI4Fc5VGfEk0epiBxdDLMJX2abW90X4tO04rhW1YSXJAkDkdzf4DrcGINd
GMSxDkgXTiuetdhM1A/je+zhndnkWeNeF+ysLhpoJcWIjdy3z5bnVD+OTCU6AFMp
X3UjUWWN6u6gqOGi190p8rpQ47/zvndkO9gsmJggbXhifue0gltKDPxyonCRjAef
cdS8o1pC14XO9swg2vd5FTLexTkf2bXKR/rYGz9+692obt093h85Mu8UPxpVOkLe
a8v3Ws/gW+RW8CcMW56cQy1Vf4OiMdjpxo2fHyRf8AiU2JAgrukEuU94CyX6/atG
MQwCOdK4VkwcxidBZvo25sFDkqB1XYncJw46pstgPAIhJffzl5oLu+KpaGvE7YXj
shvJ5fOUx7UIIjm0RU7DGGCSMto0bOuw23uLGDJWdxU7UyoITWHNC9AlN4MkR9n+
4UzX2o5gE8/D42/4fBSj/WqYVVBUMefks07MNw6OIVWMU3n08+ZPnf9qKXVHATlY
UVDiTw==
-----END CERTIFICATE-----

View File

@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDl9fKTGnY/djZF
Q9GTyaYL5/Gm2SILW1vtJCtiaLSz+NFYZiDIay8f9xGhN4eG6eCCAI1rEjt6/kVP
ZsS6qqSKCbRzmvvQKHKxe0s+F2F1VxV7ANyp3NFvLf7TJ/a961YPheALpIqC/XOr
q/ZYob++RmS7UZZJTnnkHg+e0Ah0J/LNEepSirqGVhzoNkXBw8gAUZ1HePUd7ybv
Ke8S6MGOuNuQeGNd18NcKlzEl/LEVt1EIBsx5r3ZkRTbhCiYdFzreJGAhk4e/q+X
/AfgCN17zYNxe/Pzlz/9/ZD3YlDW8ZzwhTyDCihfe6cfCzun93JYyCpU3EYfooMv
EvHQk9VLAgMBAAECggEAAtqdWbsF1/USRBHxnbS3nDLug3s8Ptuxw0zkHc5VAYHw
h8JB3OZUyS2zlqsgQhwr9VfwRMz8oGvuJ9oLlyQNvEmxQrScD9+mWeTTMJdMsY6d
6NhAQEO30ENaOsVdalz9113oDLYVkJAvaYjymvO1PSMVg/VX5qSUC/oUY7EdaJnm
3gcEvDrOogftCv281YHksCz1FNmC3vwFb4gLTvCAWUB/cJCyjL+rQYStkT/acaiC
BloDx69Pj1EFNwr47LDR7MSBsNdlw0p7uzLYoQMKFMoNIvuGhuhQwLbPd6P14JmN
PehKZ9hfj2dvxwUrFZmb0AGnMfyQPf6OAXzjdAVrSQKBgQD7QyQMppIe6XZtF6br
xGpSEUWPhFEQx4pHderT/dVewdxw4lHmF7r2RG/1kguDJ3WZnXl1X+Z17thGEm6R
x98AR2OLX0rRvuBO+wwojv54Hud+kauCDrR4Di6KyWoXJ9PcPH3NMhJkJMuSXRFA
txOZjc08tSZoAVkvTG1FtgchUwKBgQDqS/ucCWod2w/0Uf064z53SJGVAYk8bCU1
C5BzSJLsn60OA1XphKIG1ZuH+etiEz05fQwWy768q27VMgPn/XhS8jpVlVKtPIre
Ek/9wbBTvwMiP0+NyubMvRHlMRhHW0JQIJsWJ9+Pmh+8ZTvXZxscslQYS5eUhGrq
V6zz05elKQKBgHmsMbDOmMPPWkHJylMxcir7oiu1b2wotJWWTHkL2l9gkVc4wWAi
7a6DxZOtfVWtrg0NbNuh7P//AUwtcM23dA22hEXhh2G6hPS6LVEWrbONg5yO/fal
GE9qzq72iiFccAOeZ20OakmEZ/AgkVI9VYhuWoyjTE3hGUcGQ4QWea1xAoGBAIbX
0ClPqckhCJ+eiFVZ79uK4m6VgbxKqWdMDoiq3hRdGaYU+V76PJ4eVfL+PSAm3ne1
pj2AaXgAWjtNG75qvNNQIY6b8AdP7sQ8Wdk7nhW0u0L8mPaMLiTrM99qUATRWuru
uRMZQ6tMErPEt5oS9yGe6JNK/iQ1yaqxZxK1VnNxAoGAaRobzEGoITacIIG1KH0N
exVFufz9jeNLQcOk4iWp6i/7mPMcqnS67+17MvCysOlR3rBSaMG6EN8NWtiuu4a+
oPpm2ihJyyfarKJdJeqIYlZ/Tiv5NkYkP32HIzR6gjkajix3ZDxPCgwI1RJ3kb6z
LnZ4ySq5r3Llw6QiOeLbk8w=
-----END PRIVATE KEY-----

View File

@@ -1,26 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEZDCCAkygAwIBAgIUegEAdDIUZsPJiiT5lRJ8Cx+PEP0wDQYJKoZIhvcNAQEL
BQAwNTETMBEGA1UECgwKUmVkaXMgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUg
QXV0aG9yaXR5MB4XDTI1MDMxOTEwMjQ0OFoXDTI2MDMxOTEwMjQ0OFowKTETMBEG
A1UECgwKUmVkaXMgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkqQh7ChlWSYNaeXqwtGLovggr7bLKhI8eF6K
m/1sC7o/7bvDk6u35k/yUJ/9OT8Mo0oG8yPi76GL4vtxkoPWxuoVPLNQOOUap80t
Fxi2kZYWGjRAJqBGkvkcwCTdpVeR+hs5HA3P0Rsqy/vzxBLRTg+blj4+CAfucJ5b
2S5ptwML0+kOEAxLak3gHizOg20YYvozUmjGY17V+kgiOlfNnI6anC8C/jizLzdM
q6wqBMmll2bz2/13wo0nmAPUVCTT1fsfs3m1RzX10mDN/dtTCJsfF7pGx+RJfmPt
e5s1Rx+v0O+xK8R7tQFyEQDgpyf2eGxNAbudg1u0Xsve0happwIDAQABo3gwdjAL
BgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMBQGA1UdEQQNMAuCCWxvY2Fs
aG9zdDAdBgNVHQ4EFgQUdXzMnEB9vRMWmcX3mytj1sbLogswHwYDVR0jBBgwFoAU
hS4gD/EQQ8DPKZSldA9FUnp8yJAwDQYJKoZIhvcNAQELBQADggIBACvuBVMArk/J
p2WEUMsybKcHBLRSHw0BtCxit9H//o79dVnVTecZppN/ju+JX/jY2CJwE868JV7C
KdBE6FqvlmrGR6mKUjBb5FQ1XnRlVvaKYQcFNFjA1e4NrX1Zz88JfKCF9S7A3Lq3
tdJftezTNpt35cpIhd7IO4ZiIwDbMhe1k1I/nHNwOKEFgUo6oBU9LiskYrQxzXzB
J4PkKdEM3Ur/mhhM5LueRknb+iC/YEQ3wOYHuMiH+me22w1PDDkAm6lwgbZNnAsm
+oR0D3ZbfBxG17osb6HdUgf40vy8MLPJvAFAZuzXFsxD5NsffEEJxIvCb4lNSHvx
Qm2WLc9h13bVnGlJYJpXZhxMCFN4PTQ5nL6BmalOEeinac9nJlAwrkzJPZWuiQ/h
NsDmURTKbLAvbIhaULhYwb6oOXCWpGGgICNyQqBdp7n+l7dtRWZCDO8Ztd50q0rh
UnWRqYt4XP+J8InWBLbXPswEc/YsYv1Mum4gRljkprumWE0VVX7HHOd3NoDa//0O
t9oM2bgqiP6TPf9Bsxj2fSfiaBT0KOPPjp8tEZ06UNAFLx5ABnKMw7jjvRCBWsT3
1SALCeqM91ttqeL+S3rM/tTZeKspKfozGXUmOT92YqikkmtTOIX8JTp7+Oe92WWF
SDH6WM8DOTqpzkJho0w39hs8bdTrqU6S
-----END CERTIFICATE-----

View File

@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCSpCHsKGVZJg1p
5erC0Yui+CCvtssqEjx4Xoqb/WwLuj/tu8OTq7fmT/JQn/05PwyjSgbzI+LvoYvi
+3GSg9bG6hU8s1A45RqnzS0XGLaRlhYaNEAmoEaS+RzAJN2lV5H6GzkcDc/RGyrL
+/PEEtFOD5uWPj4IB+5wnlvZLmm3AwvT6Q4QDEtqTeAeLM6DbRhi+jNSaMZjXtX6
SCI6V82cjpqcLwL+OLMvN0yrrCoEyaWXZvPb/XfCjSeYA9RUJNPV+x+zebVHNfXS
YM3921MImx8XukbH5El+Y+17mzVHH6/Q77ErxHu1AXIRAOCnJ/Z4bE0Bu52DW7Re
y97SFqmnAgMBAAECggEAMSICZbShRI3955IMJyt7rGaT2RwXlWiXz0LqEVsHhSRq
ABct8AAUtXvq9j2s5C3uZ5XJn1TSWDUaADr8cjlvUKWk6PoxsmZ9GGUkKv1ySnRt
wmjoZ6jDDMKf8fdINnqRZCoT6ATusSL3o3IvWm5tp8iN+nivYxR5PU2p+6pT7Gf8
i2WFC/KPCllP82zZIWljK8UZ8i4zyazpcTnvhkOJ1oVqJ8EtmJPDcYGknNDvFpbO
PcM4ApNEbDzx/rH7JDHnuZaz0RC2k0KsYSM7r3vNG3INDv6Xcvu9aHEZ95dsx0if
j5l7U+ayhZe8I4nRCSUB70XmNaByP9zUeI4yyONnKQKBgQDCceqWgFxaxL18klTU
MQrOde5LhJx/JGrerX/fLyPtrjQPw20mCKBjvoKvBOy9SpEn06X22l9YsM+3A17x
ezWppliSjoPdn/AWfOErdiB141XMcgNfQjVUbJkxLqBywhLIPqg4um5XoVK7y4hB
xtSHe74CSKKOFmOiehR1jgdVXwKBgQDBECDXpN0KXzmcukx5KWSYnjch1H/yEkad
1oJ6VkagQh2zgNT3kokaDDQjrSFSL9lQfpXWaep40jKagKCBJfjcEb/nAPz1S4rH
CMqGPpdl6Cljrf16mOlj50Mb8BHMW2D2j7s4p8fc/hUWT0m8VOE7stsxuissRsf5
rK24GUEIuQKBgQCAngWEI8fzKmwEeG6wJPh29L75KPCzkQ032h/ZKz9iunYpbyVF
oTMmhx++UU2fMDGv3GnNTUkAS4Q6FHq61Lr8StIPr0E+WcrftR7kNrDmCcf5AfmF
CzBndaYnSCZNgl4WIov3aioOwOEO42RvzetK6ukWbaFIxzqEgKgD0jy7lQKBgQCB
PmvOEQcMp3zpB+qj/erjJJ+h3SEeC9AMYAsPHOzA4iICBhAMAKQZtOu+qmsxGukv
Mt7aICOgaI8J0WwhqSr1IEjIu2ecSssHvUHfJs2xof77RQH47Z7oi2voqwkvNkku
JkBeiCuLLOku+ztQgb4aefy1SH0YcfXzlf7hzL41uQKBgQCnvaVYcjMgNDZiMRYp
BLu4zq5MK3Wif6LwGtCG7tPWGw5dQLbVTz/pRDCpm3qpu7SQMw1N/cAFJ3HwE2hj
fAh0j1kxW12imOboXkuUr4vHid4a1VcLGQOXN2A127NS6qQk+iSP0Unh1sX541l4
tg1c7/8g2sWQBiZ6MxvLvlE7sQ==
-----END PRIVATE KEY-----