Add grpc nginx sample

pull/142/head
Baohua Yang 2022-02-03 15:29:18 -08:00
parent bc6e104434
commit f691010782
18 changed files with 665 additions and 0 deletions

20
nginx/README.md 100644
View File

@ -0,0 +1,20 @@
# Nginx samples
## Nginx auth
Nginx serves as a proxy, and requires simple password to auth to access backend.
## Nginx https
Nginx serves as a proxy, and terminates the ssl from client.
Nginx1 (ssl terminate) --> app
## Nginx https 2
Nginx1 serves as a proxy, uses mutual tls to connect with nginx2, then nginx2 terminates the ssl from HTTP client.
Nginx1 (mutual tls) --> Nginx2 (ssl terminate) --> app
## Nginx gRPC 2
Nginx1 serves as a proxy, uses mutual tls to connect with nginx2, then nginx2 terminates the ssl from a gRPC client.
Nginx1 (mutual tls) --> Nginx2 (ssl terminate) --> app

View File

@ -0,0 +1,30 @@
version: '3'
services:
nginx1:
image: nginx:1.20
container_name: nginx1
volumes:
- ./nginx1.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
ports:
- 7050:7050
nginx2:
image: nginx:1.20
container_name: nginx2
volumes:
- ./nginx2.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
ports:
- 8050:7050
grpc_server:
build: ./grpc
container_name: grpc_server
expose:
- "7050"
command: grpc_server
grpc_client:
build: ./grpc
container_name: grpc_client
command: bash -c 'while true; do sleep 20220202; done; grpc_client'

View File

@ -0,0 +1,3 @@
FROM golang:1.17
ADD hello /go/src/hello
RUN cd /go/src/hello && ls -l && make install

View File

@ -0,0 +1,17 @@
proto:
protoc --go_out=plugins=grpc:. ./hello/*.proto
install:build
cp grpc_server ${GOPATH}/bin
cp grpc_client ${GOPATH}/bin
build:
# GOPATH=/go
go build -o grpc_server server/server.go
go build -o grpc_client client/client.go
server:
# GOPATH=$(PWD)/../../
go run server/server.go
client:
# GOPATH=$(PWD)/../../
go run client/client.go
.PHONY: all proto server client test

View File

@ -0,0 +1,77 @@
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"google.golang.org/grpc/credentials"
"io/ioutil"
"log"
"os"
"time"
"google.golang.org/grpc"
pb "hello/hello"
)
const (
defaultAddress = "nginx1:7050"
defaultName = "client"
serverCert = "/go/src/hello/server1.crt"
)
func loadTLSCredentials(caFile string) (credentials.TransportCredentials, error) {
// Load certificate of the CA who signed server's certificate
pemServerCA, err := ioutil.ReadFile(caFile)
if err != nil {
return nil, err
}
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(pemServerCA) {
return nil, fmt.Errorf("failed to add server CA's certificate")
}
// Create the credentials and return it
config := &tls.Config{
RootCAs: certPool,
InsecureSkipVerify: true,
}
return credentials.NewTLS(config), nil
}
func main() {
// Set up a connection to the server.
address := defaultAddress
if len(os.Args) > 1 {
address = os.Args[1]
}
tlsCredentials, err := loadTLSCredentials(serverCert)
if err != nil {
log.Fatal("cannot load TLS credentials: ", err)
}
conn, err := grpc.Dial(address, grpc.WithTransportCredentials(tlsCredentials))
// non-tls
// conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
name := defaultName
if len(os.Args) > 2 {
name = os.Args[1]
}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting from server: %s", r.GetMessage())
}

View File

@ -0,0 +1,11 @@
module hello
go 1.13
require (
github.com/golang/protobuf v1.3.2
golang.org/x/net v0.0.0-20190311183353-d8887717615a
google.golang.org/grpc v1.24.0
)
replace hello/hello => ./hello

View File

@ -0,0 +1,27 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -0,0 +1,197 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hello/hello.proto
package helloworld
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// The request message containing the user's name.
type HelloRequest struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HelloRequest) Reset() { *m = HelloRequest{} }
func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
func (*HelloRequest) ProtoMessage() {}
func (*HelloRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_hello_3089f6170318367b, []int{0}
}
func (m *HelloRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HelloRequest.Unmarshal(m, b)
}
func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic)
}
func (dst *HelloRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_HelloRequest.Merge(dst, src)
}
func (m *HelloRequest) XXX_Size() int {
return xxx_messageInfo_HelloRequest.Size(m)
}
func (m *HelloRequest) XXX_DiscardUnknown() {
xxx_messageInfo_HelloRequest.DiscardUnknown(m)
}
var xxx_messageInfo_HelloRequest proto.InternalMessageInfo
func (m *HelloRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
// The response message containing the greetings
type HelloReply struct {
Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HelloReply) Reset() { *m = HelloReply{} }
func (m *HelloReply) String() string { return proto.CompactTextString(m) }
func (*HelloReply) ProtoMessage() {}
func (*HelloReply) Descriptor() ([]byte, []int) {
return fileDescriptor_hello_3089f6170318367b, []int{1}
}
func (m *HelloReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HelloReply.Unmarshal(m, b)
}
func (m *HelloReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HelloReply.Marshal(b, m, deterministic)
}
func (dst *HelloReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_HelloReply.Merge(dst, src)
}
func (m *HelloReply) XXX_Size() int {
return xxx_messageInfo_HelloReply.Size(m)
}
func (m *HelloReply) XXX_DiscardUnknown() {
xxx_messageInfo_HelloReply.DiscardUnknown(m)
}
var xxx_messageInfo_HelloReply proto.InternalMessageInfo
func (m *HelloReply) GetMessage() string {
if m != nil {
return m.Message
}
return ""
}
func init() {
proto.RegisterType((*HelloRequest)(nil), "helloworld.HelloRequest")
proto.RegisterType((*HelloReply)(nil), "helloworld.HelloReply")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// GreeterClient is the client API for Greeter service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type GreeterClient interface {
// Sends a greeting
SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
}
type greeterClient struct {
cc *grpc.ClientConn
}
func NewGreeterClient(cc *grpc.ClientConn) GreeterClient {
return &greeterClient{cc}
}
func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
out := new(HelloReply)
err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Greeter service
type GreeterServer interface {
// Sends a greeting
SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}
func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
s.RegisterService(&_Greeter_serviceDesc, srv)
}
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(HelloRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GreeterServer).SayHello(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/helloworld.Greeter/SayHello",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Greeter_serviceDesc = grpc.ServiceDesc{
ServiceName: "helloworld.Greeter",
HandlerType: (*GreeterServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "SayHello",
Handler: _Greeter_SayHello_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "hello/hello.proto",
}
func init() { proto.RegisterFile("hello/hello.proto", fileDescriptor_hello_3089f6170318367b) }
var fileDescriptor_hello_3089f6170318367b = []byte{
// 144 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcc, 0x48, 0xcd, 0xc9,
0xc9, 0xd7, 0x07, 0x93, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x5c, 0x60, 0x4e, 0x79, 0x7e,
0x51, 0x4e, 0x8a, 0x92, 0x12, 0x17, 0x8f, 0x07, 0x88, 0x17, 0x94, 0x5a, 0x58, 0x9a, 0x5a, 0x5c,
0x22, 0x24, 0xc4, 0xc5, 0x92, 0x97, 0x98, 0x9b, 0x2a, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x19, 0x04,
0x66, 0x2b, 0xa9, 0x71, 0x71, 0x41, 0xd5, 0x14, 0xe4, 0x54, 0x0a, 0x49, 0x70, 0xb1, 0xe7, 0xa6,
0x16, 0x17, 0x27, 0xa6, 0xc3, 0x14, 0xc1, 0xb8, 0x46, 0x9e, 0x5c, 0xec, 0xee, 0x45, 0xa9, 0xa9,
0x25, 0xa9, 0x45, 0x42, 0x76, 0x5c, 0x1c, 0xc1, 0x89, 0x95, 0x60, 0x5d, 0x42, 0x12, 0x7a, 0x08,
0xfb, 0xf4, 0x90, 0x2d, 0x93, 0x12, 0xc3, 0x22, 0x53, 0x90, 0x53, 0xa9, 0xc4, 0x90, 0xc4, 0x06,
0x76, 0xa9, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xa5, 0x8f, 0x93, 0x76, 0xbe, 0x00, 0x00, 0x00,
}

View File

@ -0,0 +1,19 @@
syntax = "proto3";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}

View File

@ -0,0 +1,37 @@
package main
import (
"context"
"fmt"
"log"
"net"
"google.golang.org/grpc"
pb "hello/hello"
)
const (
port = ":7050"
)
type server struct{ }
// implement server side interface methods
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received msg from: %s\n", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
// start a gRPC server side: create socket, create, register and start the service
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v\n", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
fmt.Printf("Starting listen on port: %s\n", port)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDfTCCAmWgAwIBAgIURFu7iX8+iLUXefTUMhV5HkviJJ8wDQYJKoZIhvcNAQEL
BQAwTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQowCAYDVQQHDAFPMQowCAYD
VQQKDAFPMQowCAYDVQQLDAFPMQ4wDAYDVQQDDAUqLmNvbTAeFw0yMjAyMDIyMzU0
MjFaFw0zMjAxMzEyMzU0MjFaME4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEK
MAgGA1UEBwwBTzEKMAgGA1UECgwBTzEKMAgGA1UECwwBTzEOMAwGA1UEAwwFKi5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRVhWlCMpKJAaWVI+U
aOF82vttfGECi28ZdUqgeaQnniOxGC2fQ66pJSmltTiYVTH3IRRbax/pGgUdqt1E
gGB2jLqqbcqMxlzg4mSThO/cT2/3cFjoeOyg6yC2RjB8FjTjFrkWqiEenubqnqSX
DC7XB6icYuimRPhMCLhC6GX/nPwfTMc98vzi9icOVZet84s5pReRQcSEd5ndg5+L
OnCgivwFSXsjVZudpojXmdZ2Izb9fVQAhKZTgHe62rF1RZ2wkAmnOo1Haybe89vN
Cm8lbIcoQKgPFlsqt3fa1kL80opHwrj6wDVMZ1dXGLULZ1EdGowymgso29o+Ojuh
3n2NAgMBAAGjUzBRMB0GA1UdDgQWBBQkfe744BxH3XaZlWvXq54YFmp9MDAfBgNV
HSMEGDAWgBQkfe744BxH3XaZlWvXq54YFmp9MDAPBgNVHRMBAf8EBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4IBAQCuH6jvESJQAzBGnKTHNlLmaX5OWJ2tFx78mRkLgbPC
kL1uTwH7aQfga+TjnEPT5rSftnATaR0k8vxLSIT3KEpHrFZ4hHr1UwqikJGkmAYa
TlFXLvX8eX8bo6NxECHz7OBOGzvUxBY9tm7NdojHk7XfOY5gJSbnpFQxNcdpk7jd
y56nqAI/zhaDoCcrdxpvEBT657+NAaBfCJeH8ivudAQffaAJ9/c68HWHCr+tyQQw
Vr6s6QMMKAZWJhUNKFVhNZczT+WcpqbQEuab1LJsut4pm72CUayq92vm7+jwiyCP
TaKrNkcWug74xzzxvZtvtAO8rKRjyI/VZRB8sT6W2ey6
-----END CERTIFICATE-----

View File

@ -0,0 +1,52 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#include /etc/nginx/conf.d/*.conf;
}
stream {
upstream nginx2 {
server nginx2:7050;
}
upstream backend {
server grpc_server:7050;
}
server {
listen 7050 ssl;
#proxy_pass backend;
proxy_pass nginx2;
ssl_trusted_certificate /etc/nginx/ssl/server1.crt;
ssl_certificate /etc/nginx/ssl/server1.crt;
ssl_certificate_key /etc/nginx/ssl/server1.key;
proxy_ssl on;
proxy_ssl_certificate /etc/nginx/ssl/server1.crt;
proxy_ssl_certificate_key /etc/nginx/ssl/server1.key;
}
}

View File

@ -0,0 +1,47 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#include /etc/nginx/conf.d/*.conf;
}
stream {
upstream backend {
server grpc_server:7050;
}
server {
listen 7050 ssl;
proxy_pass backend;
ssl_trusted_certificate /etc/nginx/ssl/server2.crt;
ssl_certificate /etc/nginx/ssl/server2.crt;
ssl_certificate_key /etc/nginx/ssl/server2.key;
ssl_client_certificate /etc/nginx/ssl/server1.crt;
ssl_verify_client on;
}
}

View File

@ -0,0 +1,9 @@
openssl req \
-x509 \
-nodes \
-days 3650 \
-newkey rsa:2048 \
-keyout /root/server2.key \
-out /root/server2.crt
# Enter "*.net" (without quotes) as "Common Name"

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDfTCCAmWgAwIBAgIURFu7iX8+iLUXefTUMhV5HkviJJ8wDQYJKoZIhvcNAQEL
BQAwTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQowCAYDVQQHDAFPMQowCAYD
VQQKDAFPMQowCAYDVQQLDAFPMQ4wDAYDVQQDDAUqLmNvbTAeFw0yMjAyMDIyMzU0
MjFaFw0zMjAxMzEyMzU0MjFaME4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEK
MAgGA1UEBwwBTzEKMAgGA1UECgwBTzEKMAgGA1UECwwBTzEOMAwGA1UEAwwFKi5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRVhWlCMpKJAaWVI+U
aOF82vttfGECi28ZdUqgeaQnniOxGC2fQ66pJSmltTiYVTH3IRRbax/pGgUdqt1E
gGB2jLqqbcqMxlzg4mSThO/cT2/3cFjoeOyg6yC2RjB8FjTjFrkWqiEenubqnqSX
DC7XB6icYuimRPhMCLhC6GX/nPwfTMc98vzi9icOVZet84s5pReRQcSEd5ndg5+L
OnCgivwFSXsjVZudpojXmdZ2Izb9fVQAhKZTgHe62rF1RZ2wkAmnOo1Haybe89vN
Cm8lbIcoQKgPFlsqt3fa1kL80opHwrj6wDVMZ1dXGLULZ1EdGowymgso29o+Ojuh
3n2NAgMBAAGjUzBRMB0GA1UdDgQWBBQkfe744BxH3XaZlWvXq54YFmp9MDAfBgNV
HSMEGDAWgBQkfe744BxH3XaZlWvXq54YFmp9MDAPBgNVHRMBAf8EBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4IBAQCuH6jvESJQAzBGnKTHNlLmaX5OWJ2tFx78mRkLgbPC
kL1uTwH7aQfga+TjnEPT5rSftnATaR0k8vxLSIT3KEpHrFZ4hHr1UwqikJGkmAYa
TlFXLvX8eX8bo6NxECHz7OBOGzvUxBY9tm7NdojHk7XfOY5gJSbnpFQxNcdpk7jd
y56nqAI/zhaDoCcrdxpvEBT657+NAaBfCJeH8ivudAQffaAJ9/c68HWHCr+tyQQw
Vr6s6QMMKAZWJhUNKFVhNZczT+WcpqbQEuab1LJsut4pm72CUayq92vm7+jwiyCP
TaKrNkcWug74xzzxvZtvtAO8rKRjyI/VZRB8sT6W2ey6
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDRVhWlCMpKJAaW
VI+UaOF82vttfGECi28ZdUqgeaQnniOxGC2fQ66pJSmltTiYVTH3IRRbax/pGgUd
qt1EgGB2jLqqbcqMxlzg4mSThO/cT2/3cFjoeOyg6yC2RjB8FjTjFrkWqiEenubq
nqSXDC7XB6icYuimRPhMCLhC6GX/nPwfTMc98vzi9icOVZet84s5pReRQcSEd5nd
g5+LOnCgivwFSXsjVZudpojXmdZ2Izb9fVQAhKZTgHe62rF1RZ2wkAmnOo1Haybe
89vNCm8lbIcoQKgPFlsqt3fa1kL80opHwrj6wDVMZ1dXGLULZ1EdGowymgso29o+
Ojuh3n2NAgMBAAECggEBAKXxh9b70OBVDqO9BNSxD47aSNXR81UBE2ErCa2MwARn
6ANLF19ZV+vd+dXSgrq/ToyJPIn7saAncEbEXAMhgVZ42MChqB9QX/Alh3UpvLr4
fdm4xcIDmhE2UwgrO+Qh9mrOaIr+8qJDdOooOHFExxzOhWrzPVoQ8oPTpb3kXHbz
nB9OiTertbw4YHABx9+7Xg+L3d/4+69khYaG369HonnJMc/4YIsgHhomv7x1fWzg
LSSIiUyHMnhPss8hWAL0YBIkfB+XwwEJ1tt45QZCr2GVICZ+AzU1j6DnxM4/V8lF
QWZq2FiwbWvXLo89m4ZrqfhgzxoTK9cuULw37fPv2gECgYEA6aLidpJ6UwvNZRkL
soOV0UfWKAJoAt5L6Uz6J32rg1jIKSKg5qzk7dp2u24iVriCA8chOnVia90bpbQ5
gTX3zNlpBedly7rZvZQJnbr82xFBkJfRU5AZ90W+RLWPijAZjp5MYKBEuVbs84Q9
eFpZT/nz563isJo6In5vSay8KHkCgYEA5V++PWbawXQ4x2+PyglQunFTZy6M/Fha
QtdGqL87bK6Xo9my/As2NhvH/2HLGgXcXGxq2ppE2E59NOZIsUpcEj9Hvhyb5e5E
0Rn0kX1Rq417xIVn8zBqgjd8DKQc07ih6JqANNtste0ZIGHQ2xC7xTKNBYTxCXTh
EVc0n0XM4LUCgYBssu7AEdg9qQEPpz5s+JGMg+qcRLpVk00oJzs/glV4z6aYlNbd
W9VK4FhbTZtGU6OR1GSeSRzYaE/DoX0bo5s9wGz/ZTBUQAOsEyMCMowP9BBYEHpA
cYvTIqyqVPqKZWSOmRGZ5xbyUAIALidXRlnFPtp+kMUmOysO/1oRof8MqQKBgQCe
miltQ6WXhsmL/bQrO226vYmyGxoZku42sayGGlT4vXDVNz7v0MDXgTY1fGV3xP2u
Wrk4FtvrxboFzgYNsSEg7OiqqBWUU8D55TybLVA/k0E1jhlmqt+60qrQAtp7+3rY
35wu8FqnIR7yqTBFibiMjnu8iUQyCcNmvioAx7720QKBgQC9pafeUYCRYlz0mYFN
p4S4GPKO7E2s/UVt/c9PLWMFoSqc07VosuY4JgmYLFsB1lnOL3WvxP3A+8If1NEz
xJ7bpLcTIxwvabJBDgkcCVHJo3J46ze/gIMppu7J9SuGYc0Yr4gcZcF9jiPxdFxE
3WTHcQzWfnv1cSEfzWLHk2zAbg==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDfTCCAmWgAwIBAgIUB8iDeBEFCI5nB+ZcptyBiK8CSugwDQYJKoZIhvcNAQEL
BQAwTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQowCAYDVQQHDAFPMQowCAYD
VQQKDAFPMQowCAYDVQQLDAFPMQ4wDAYDVQQDDAUqLm5ldDAeFw0yMjAyMDMwMDI4
MzhaFw0zMjAyMDEwMDI4MzhaME4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEK
MAgGA1UEBwwBTzEKMAgGA1UECgwBTzEKMAgGA1UECwwBTzEOMAwGA1UEAwwFKi5u
ZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZfsjmr38jGNBlwXcU
tLKN3JgK8O8kMO7izg8tnFCag9RdDMmm+Xq+ntpCzzNHVzK+K9m60AML4dnalHU+
5FJqe++iR3092JxOOlh7D2QYsq59mttlXLPxvwB+Hn7/Bp7l4Y4WlSuQ9ViigLi2
GwFmu/4rQuHEpm3PeaLRrZObnmDmwWdYE4Y1XMwWy7PfQp+6Hl/Eq9ZuhU+c0gzo
hlenmBSAfZK0ctYbAP/zGUqbBup+wuhZOyx2gEGnCDgKg9POjSqXIb+dqcOjvaJo
5CWjuSodiX1bjeUYR4uC+wxY/k38EzcVlbGB8f/UFNwmYg2tY/bB54toj5mNc/f6
KiNDAgMBAAGjUzBRMB0GA1UdDgQWBBQO64TaLjr1mC9yuIQVnIp3+xvPHTAfBgNV
HSMEGDAWgBQO64TaLjr1mC9yuIQVnIp3+xvPHTAPBgNVHRMBAf8EBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4IBAQB6ybZzfFMWG2CNZBvvlSi2RoIOoQ7Ra9QD8aC6py5j
zJi3RVV/NxJz7ODdE3Y8uOo8Gi7owQCFBrKXESKTsoT+uoD1mV7sWqXTkjgVNbMJ
lbOpTdZisWG4/6BLVKIYf1TnEv5uWzr9k/2VP86LLZra/T0fntE6qFfBISXBicTt
uePPO3v2EW4u19hqdXgZz5UxpCJoAGV2H+HGknvhqzoiEy6IWGfda7QU0vyvrjiU
SPlz9mlSbWIBlP34aay37OET9yD0jqakg7r7Uvc2daBa4vkaZyNn4IIuw13rr2fV
6oUX5Y2bioaF+2BwVzz5A0O9qShuzTbFiqgRLcQyPadr
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZfsjmr38jGNBl
wXcUtLKN3JgK8O8kMO7izg8tnFCag9RdDMmm+Xq+ntpCzzNHVzK+K9m60AML4dna
lHU+5FJqe++iR3092JxOOlh7D2QYsq59mttlXLPxvwB+Hn7/Bp7l4Y4WlSuQ9Vii
gLi2GwFmu/4rQuHEpm3PeaLRrZObnmDmwWdYE4Y1XMwWy7PfQp+6Hl/Eq9ZuhU+c
0gzohlenmBSAfZK0ctYbAP/zGUqbBup+wuhZOyx2gEGnCDgKg9POjSqXIb+dqcOj
vaJo5CWjuSodiX1bjeUYR4uC+wxY/k38EzcVlbGB8f/UFNwmYg2tY/bB54toj5mN
c/f6KiNDAgMBAAECggEAEq1sm0Le7CipXNOsYj7SRpR3Chl+r+Dz4s5HR2dxFJPV
nNgISSqLe+swWyRoBuxaEzK40+4hFNgkWTz+hJQe774M6iaxfqonYiBokMjVk7lk
eqzdwmqfmVcJt8rupP/wjVU9Wnsc7qnjHrFnK1xOVoA2Z4iq0rRoIbUUYmVBk89x
cFH2bFQWLghry8pOa4lzwLPnD8BFduTNKk8GZWlQIIh+Pbtp24KhM6pau0qHZnyT
qPb8ZNzt71hWKYHIsqqB6BQm0EizhKg8Aax21cdUP61YAq15IxcaXppmVaNrpCJK
yDxLLsRY1JygTCZ8jiaA2KDs31k0hAbYNDi3x3q3AQKBgQD65MAcexwfsSQ5RrIK
8HKFAhmc2qPiXWTyLlDzXrVlaHEv8adVuuq/0mYlRl6EONyUw8Wxk6BtQw4NoCp8
FWpFE1b5ORqE9uKxNNWXoKPvyg8g4ALvdgqDvxHBT69XE3c43aTiz+snUhgog1MM
7PNuqiI5ix0DGIZS1rG9ZYSl4wKBgQDd7ARCwNUUizLZlLCTYRTprUykLkqsPFOr
5Dcycf6Li1wTw1gq1DXQfkywke0NS/gFDr8bqylyxUO88wlNIYf5PB5oekCNMZ1g
OEz/8gASmQAchpnZYQtpGDhLYZzMZjC074fUCrySJiQ3WS6U+OI0ES+odaaDWBIu
YBwcXlALIQKBgQD0TxXHZhYPwkX8xBuRTWymmlHojHszbTBkJ7fKFLpcoiQ9xHnm
oFoBKlcvCuP0qw4Yir6SWafJXZdsqz9TjuLpmpiBnRp2yZYbatBmkxWv5TlwENKq
7W31tnQKopaiGyFoLWRnPIHGy0kdAiw4FPBDHcav9AfvQM1kEw4G2LkfcwKBgQCK
12CLCu3E3pm/uuEGM9TLpdqvVS7utwd6IVvPObaRQ20mCC8fDIlmmb4NMh7nFMJl
F6bE/r79ySDqE/ubwAC8E7rKjsHYFFRroI28C4G0IPkK38NdVvO2mqqNrtJUpxKO
ANYv+U+k+CvsXOVh2pxbCu2QLZsxzWYCkarErNTTQQKBgFbdLb1GRQvZRblxAUuv
p75DiebRyCBsY6yXYc03VmsKw7N0+gehqh8pYPeN736GIkQH/4Ufbf8Fswe1Cnms
fpZfKm/3DovMrMMiA+BWInA+Yhra6c186k/wq0wmhRtUkvbZN70n2FJ3vQ9kbphn
+G/n6zv32ON3qsiZHVqTdvyl
-----END PRIVATE KEY-----