mirror of
https://github.com/paralus/paralus.git
synced 2026-08-23 13:26:15 +00:00
@@ -0,0 +1,50 @@
|
||||
# Build the manager binary
|
||||
FROM golang:1.16.6 as builder
|
||||
|
||||
WORKDIR /workspace
|
||||
# Copy the Go Modules manifests
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
|
||||
# setup github user and token
|
||||
ARG BUILD_USR="nothing"
|
||||
ARG BUILD_PWD="nothing"
|
||||
|
||||
# Create the user and group files that will be used in the running
|
||||
# container to run the process as an unprivileged user.
|
||||
RUN mkdir /user && \
|
||||
echo 'nobody:x:65534:65534:nobody:/:' > /user/passwd && \
|
||||
echo 'nobody:x:65534:' > /user/group
|
||||
|
||||
# Create a netrc file using the credentials specified using --build-arg
|
||||
RUN printf "machine github.com\n\
|
||||
login ${BUILD_USR}\n\
|
||||
password ${BUILD_PWD}\n\
|
||||
\n\
|
||||
machine api.github.com\n\
|
||||
login ${BUILD_USR}\n\
|
||||
password ${BUILD_PWD}\n"\
|
||||
>> /root/.netrc
|
||||
RUN chmod 600 /root/.netrc
|
||||
|
||||
# cache deps before building and copying source so that we don't need to re-download as much
|
||||
# and so that source changes don't invalidate our downloaded layer
|
||||
RUN GOPRIVATE=github.com/RafaySystems/* go mod download
|
||||
|
||||
# Copy the go source
|
||||
COPY main.go main.go
|
||||
COPY pkg/ pkg/
|
||||
|
||||
|
||||
# Build
|
||||
# uncomment this to debug race conditions
|
||||
#RUN GOPRIVATE=github.com/RafaySystems/* CGO_ENABLED=1 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -race -a -o rafay-relay main.go
|
||||
RUN GOPRIVATE=github.com/RafaySystems/* CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -ldflags "-X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn" -a -o rafay-relay main.go
|
||||
|
||||
# Use distroless as minimal base image to package the manager binary
|
||||
# Refer to https://github.com/GoogleContainerTools/distroless for more details
|
||||
FROM gcr.io/distroless/static:latest
|
||||
WORKDIR /
|
||||
COPY --from=builder /workspace/relay .
|
||||
ENTRYPOINT ["/relay"]
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# Build the manager binary
|
||||
FROM golang:1.16.6 as builder
|
||||
|
||||
WORKDIR /workspace
|
||||
# Copy the Go Modules manifests
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
|
||||
# setup github user and token
|
||||
ARG BUILD_USR="nothing"
|
||||
ARG BUILD_PWD="nothing"
|
||||
|
||||
# Create the user and group files that will be used in the running
|
||||
# container to run the process as an unprivileged user.
|
||||
RUN mkdir /user && \
|
||||
echo 'nobody:x:65534:65534:nobody:/:' > /user/passwd && \
|
||||
echo 'nobody:x:65534:' > /user/group
|
||||
|
||||
# Create a netrc file using the credentials specified using --build-arg
|
||||
RUN printf "machine github.com\n\
|
||||
login ${BUILD_USR}\n\
|
||||
password ${BUILD_PWD}\n\
|
||||
\n\
|
||||
machine api.github.com\n\
|
||||
login ${BUILD_USR}\n\
|
||||
password ${BUILD_PWD}\n"\
|
||||
>> /root/.netrc
|
||||
RUN chmod 600 /root/.netrc
|
||||
|
||||
# cache deps before building and copying source so that we don't need to re-download as much
|
||||
# and so that source changes don't invalidate our downloaded layer
|
||||
RUN GOPRIVATE=github.com/RafaySystems/* go mod download
|
||||
|
||||
# Copy the go source
|
||||
COPY main.go main.go
|
||||
COPY pkg/ pkg/
|
||||
|
||||
|
||||
# Build
|
||||
# uncomment this to debug race conditions
|
||||
#RUN GOPRIVATE=github.com/RafaySystems/* CGO_ENABLED=1 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -race -a -o rafay-relay main.go
|
||||
RUN GOPRIVATE=github.com/RafaySystems/* CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -ldflags "-X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn" -a -o rafay-relay main.go
|
||||
|
||||
# Use distroless as minimal base image to package the manager binary
|
||||
# Refer to https://github.com/GoogleContainerTools/distroless for more details
|
||||
FROM gcr.io/distroless/static:latest
|
||||
WORKDIR /
|
||||
COPY --from=builder /workspace/relay .
|
||||
ENTRYPOINT ["/relay"]
|
||||
|
||||
|
||||
# Before copying the Go binary directly to the final image,
|
||||
# add them to the intermdediate upx image
|
||||
FROM rafaysystems/upx:latest as upx
|
||||
COPY --from=builder /workspace/relay /relay.orig
|
||||
|
||||
# Compress the binary and copy it to final image
|
||||
RUN upx --best --lzma -o /relay /relay.orig
|
||||
|
||||
# Use distroless as minimal base image to package the manager binary
|
||||
# Refer to https://github.com/GoogleContainerTools/distroless for more details
|
||||
FROM gcr.io/distroless/static:nonroot
|
||||
WORKDIR /
|
||||
COPY --from=upx /relay .
|
||||
ENTRYPOINT ["/relay"]
|
||||
@@ -0,0 +1,8 @@
|
||||
# Use distroless as minimal base image to package the manager binary
|
||||
# Refer to https://github.com/GoogleContainerTools/distroless for more details
|
||||
#FROM gcr.io/distroless/static:latest
|
||||
## use base:debug for shell access
|
||||
FROM gcr.io/distroless/static:latest
|
||||
WORKDIR /
|
||||
COPY relay.upx relay
|
||||
ENTRYPOINT ["/relay"]
|
||||
@@ -0,0 +1,33 @@
|
||||
IMG ?= relay:latest
|
||||
TS := $(shell /bin/date "+%Y%m%d%H%M%S")
|
||||
DEV_USER ?= dev
|
||||
DEV_TAG := registry.dev.rafay-edge.net:5000/${DEV_USER}/relay:$(TS)
|
||||
|
||||
.PHONY: tidy
|
||||
tidy:
|
||||
GOPRIVATE=github.com/RafaySystems/* go mod tidy
|
||||
|
||||
.PHONY: vendor
|
||||
vendor:
|
||||
GOPROXY=direct GOPRIVATE=github.com/RafaySystems/* go mod vendor
|
||||
|
||||
check:
|
||||
go fmt ./...
|
||||
go vet ./...
|
||||
|
||||
build:
|
||||
docker build . -t ${IMG} --build-arg BUILD_USR=${BUILD_USER} --build-arg BUILD_PWD=${BUILD_PASSWORD}
|
||||
|
||||
build-agent:
|
||||
docker build -t ${IMG} --build-arg BUILD_USR=${BUILD_USER} --build-arg BUILD_PWD=${BUILD_PASSWORD} -f Dockerfile.agent .
|
||||
|
||||
tag-dev:
|
||||
docker tag ${IMG} $(DEV_TAG)
|
||||
docker push $(DEV_TAG)
|
||||
|
||||
build-dev:
|
||||
rm -rf relay.*
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -ldflags "-X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn" -o relay.dev main.go
|
||||
upx -5 -o relay.upx relay.dev
|
||||
docker build -f Dockerfile.dev -t ${IMG} .
|
||||
$(MAKE) tag-dev
|
||||
@@ -0,0 +1,137 @@
|
||||
# Rafay relay-server / rafay-agent
|
||||
Relay server and agent for kubectl access.
|
||||
|
||||
## Development Setup
|
||||
Relay depends following code-repos
|
||||
1. rcloud-base/components/common : git@github.com:RafaySystems/rcloud-base.git
|
||||
2. rcloud-base/components/adminsrv : git@github.com:RafaySystems/rcloud-base.git
|
||||
3. rcloud-base/components/cluster-scheduler : git@github.com:RafaySystems/rcloud-base.git
|
||||
|
||||
Check out the above code repos.
|
||||
|
||||
Go to cluster-scheduler
|
||||
```
|
||||
make teardown
|
||||
make setup
|
||||
make run
|
||||
```
|
||||
|
||||
Go to adminsrv
|
||||
```
|
||||
make teardown
|
||||
make setup
|
||||
GRPC_GO_LOG_VERBOSITY_LEVEL=99 GRPC_GO_LOG_SEVERITY_LEVEL=info go run main.go
|
||||
|
||||
```
|
||||
|
||||
### Rafay Relay Server
|
||||
Get peer client token for relay.
|
||||
|
||||
Open the admindb postgress and execute below SQL to fetch the token.
|
||||
```
|
||||
admindb=# select token from sentry_bootstrap_agent_template where name='rafay-sentry-peering-client';
|
||||
token
|
||||
----------------------
|
||||
brhsrbbipt349qt0qad0
|
||||
|
||||
```
|
||||
|
||||
Use above token set the environment variable for relay-server
|
||||
```
|
||||
export RELAY_PEERING_TOKEN=brhsrbbipt349qt0qad0
|
||||
export RAFAY_RELAY_PEERSERVICE=http://peering.sentry.rafay.local:10001
|
||||
export POD_NAME=relay-pod1
|
||||
go run main.go --mode server --log-level 3
|
||||
|
||||
```
|
||||
### Rafay Relay Agent
|
||||
|
||||
Get the config for rafay relay agent
|
||||
```
|
||||
curl http://localhost:11000/infra/v3/project/:metadata.project/cluster/:metadata.name/download
|
||||
```
|
||||
|
||||
Use the values of relay-agent-config and apply in the cluster.
|
||||
|
||||
```
|
||||
kubectl -n rafay-system get cm/relay-agent-config -o yaml
|
||||
|
||||
apiVersion: v1
|
||||
data:
|
||||
clusterID: 4qkolkn
|
||||
relays: '[{"token":"brht3cjipt35cb3kfjag","addr":"api.sentry.rafay.local:11000","endpoint":"*.core-connector.relay.rafay.local:443","name":"rafay-core-relay-agent","templateToken":"brhsrbbipt349qt0qae0"}]'
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
creationTimestamp: "2020-04-28T07:10:53Z"
|
||||
name: relay-agent-config
|
||||
namespace: rafay-system
|
||||
resourceVersion: "3127787"
|
||||
selfLink: /api/v1/namespaces/rafay-system/configmaps/relay-agent-config
|
||||
uid: e5fb5c16-c659-46d3-805f-3a2f3b73e9d7
|
||||
```
|
||||
|
||||
```
|
||||
kubectl apply -f <file-name>
|
||||
```
|
||||
|
||||
Run relay-agent
|
||||
```
|
||||
export POD_NAME=relay-agent-pod1
|
||||
go run main.go --mode client --log-level 3
|
||||
```
|
||||
|
||||
Setup the local /etc/hosts file to resolve below hostname to localhost
|
||||
```
|
||||
127.0.0.1 peering.sentry.rafay.local
|
||||
|
||||
127.0.0.1 rx28oml.core-connector.relay.rafay.local
|
||||
127.0.0.1 4qkolkn.core-connector.relay.rafay.local
|
||||
|
||||
127.0.0.1 rx28oml.user.relay.rafay.local
|
||||
127.0.0.1 4qkolkn.user.relay.rafay.local
|
||||
```
|
||||
|
||||
Download kubeconfig
|
||||
```
|
||||
curl http://localhost:11000/v2/sentry/kubeconfig/user?opts.selector=rafay.dev/clusterName=c-4
|
||||
```
|
||||
|
||||
Save the contents to a file and use for kubectl
|
||||
```
|
||||
kubectl --v=6 --kubeconfig /<PATH>/kubeconfig-c-5 get pod -A
|
||||
```
|
||||
|
||||
|
||||
### Production
|
||||
Relay server need following environment variables
|
||||
|
||||
POD_NAME - name of the relay instaance (auto generated)
|
||||
POD_NAMESPACE - namespace of the relay instance
|
||||
|
||||
RAFAY_SENTRY - URL to boostrap with sentry service
|
||||
RAFAY_RELAY_PEERSERVICE - To join gRPC with sentry peer service
|
||||
|
||||
|
||||
RELAY_USER_DOMAIN - domain suffix for relay user facing server
|
||||
RELAY_CONNECTOR_DOMAIN - domain suffix for relay connector facing domain
|
||||
|
||||
RELAY_TOKEN - Peer Service Token bootstrapping
|
||||
RELAY_USER_TOKEN - Relay user facing server bootstrapping
|
||||
RELAY_CONNECTOR_TOKEN - Relay connector facing server bootstrapping
|
||||
|
||||
RELAY_LISTENIP - specify the listen IP if you want servers to listen other than 0.0.0.0 (usefull in testing local)
|
||||
|
||||
|
||||
Examples:
|
||||
```
|
||||
export RAFAY_SENTRY=http://sentry.rafay.dev:9000
|
||||
export RAFAY_RELAY_PEERSERVICE=http://peering.sentry.rafay.local:7001
|
||||
|
||||
export RELAY_USER_DOMAIN="user.relay.rafay.local"
|
||||
export RELAY_CONNECTOR_DOMAIN="core-connector.relay.rafay.local"
|
||||
|
||||
export RELAY_TOKEN=bqfvhabipt3a2g46986g
|
||||
export RELAY_USER_TOKEN=bqfvhabipt3a2g46987g
|
||||
export RELAY_CONNECTOR_TOKEN=bqfvhabipt3a2g469870
|
||||
export RELAY_LISTENIP=127.0.10.1
|
||||
```
|
||||
@@ -0,0 +1,114 @@
|
||||
module github.com/RafaySystems/rcloud-base/components/relay
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/RafaySystems/rcloud-base/components/common v0.0.0-unpublished
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/dgraph-io/ristretto v0.1.0
|
||||
github.com/felixge/httpsnoop v1.0.1
|
||||
github.com/felixge/tcpkeepalive v0.0.0-20160804073959-5bb0b2dea91e
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b
|
||||
github.com/jinzhu/inflection v1.0.0
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
github.com/rs/xid v1.3.0
|
||||
github.com/segmentio/encoding v0.3.3
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.8.1
|
||||
github.com/twmb/murmur3 v1.1.6
|
||||
go.uber.org/zap v1.20.0
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
||||
google.golang.org/grpc v1.43.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
k8s.io/api v0.23.2
|
||||
k8s.io/apimachinery v0.23.2
|
||||
k8s.io/client-go v0.23.2
|
||||
sigs.k8s.io/controller-runtime v0.11.0
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/go-logr/logr v1.2.0 // indirect
|
||||
github.com/go-openapi/analysis v0.20.1 // indirect
|
||||
github.com/go-openapi/errors v0.20.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/loads v0.21.0 // indirect
|
||||
github.com/go-openapi/runtime v0.21.1 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.1 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-openapi/validate v0.20.3 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-cmp v0.5.7 // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.3 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/processout/grpc-go-pool v1.2.1 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.28.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/segmentio/asm v1.1.3 // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/valyala/fastjson v1.6.3 // indirect
|
||||
go.mongodb.org/mongo-driver v1.7.5 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/sys v0.0.0-20211123173158-ef496fb156ab // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
k8s.io/apiextensions-apiserver v0.23.2 // indirect
|
||||
k8s.io/component-base v0.23.2 // indirect
|
||||
k8s.io/klog v1.0.0 // indirect
|
||||
k8s.io/klog/v2 v2.30.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220114203427-a0453230fd26 // indirect
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||
sigs.k8s.io/kustomize/pseudo/k8s v0.1.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/RafaySystems/rcloud-base/components/common v0.0.0-unpublished => /home/infracloud/development/vscode-workspace/rafay/rcloud-base/components/common/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
// Copyright (C) 2020 Rafay Systems https://rafay.co/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/agent"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relay"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/tail"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
log *relaylogger.RelayLog
|
||||
)
|
||||
|
||||
func exit(cancel context.CancelFunc) {
|
||||
cancel()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func terminate(cancel context.CancelFunc) {
|
||||
cancel()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
//os signal handler
|
||||
func signalHandler(sig os.Signal, cancel context.CancelFunc) {
|
||||
if sig == syscall.SIGINT || sig == syscall.SIGKILL || sig == syscall.SIGTERM || sig == syscall.SIGQUIT {
|
||||
log.Error(
|
||||
nil,
|
||||
"Received",
|
||||
"signal", sig,
|
||||
)
|
||||
exit(cancel)
|
||||
return
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"Received",
|
||||
"signal", sig,
|
||||
)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
flag.String("mode", "server", "mode of relay, accepeted values server/client")
|
||||
flag.Int("log-level", 1, "log leve, accepted values 0-3")
|
||||
flag.Bool("profile", false, "enable profiling")
|
||||
flag.Int("profile-port", 13000, "profiler http port")
|
||||
|
||||
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
||||
pflag.Parse()
|
||||
viper.BindPFlags(pflag.CommandLine)
|
||||
|
||||
mode := viper.GetString("mode")
|
||||
logLevel := viper.GetInt("log-level")
|
||||
profile := viper.GetBool("profile")
|
||||
profilePort := viper.GetInt("profile-port")
|
||||
|
||||
utils.GenUUID()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
log = relaylogger.NewLogger(logLevel).WithName("Relay")
|
||||
|
||||
signalChan := make(chan os.Signal, 2)
|
||||
signal.Notify(signalChan,
|
||||
os.Interrupt,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGHUP,
|
||||
syscall.SIGKILL,
|
||||
syscall.SIGTERM,
|
||||
syscall.SIGQUIT,
|
||||
)
|
||||
|
||||
log.Info(
|
||||
"Relay",
|
||||
"mode", mode,
|
||||
"loglevel", logLevel,
|
||||
)
|
||||
|
||||
utils.LogLevel = logLevel
|
||||
|
||||
if profile {
|
||||
go func() {
|
||||
log.Info("profiling enabled", "profilePort", profilePort)
|
||||
err := http.ListenAndServe(fmt.Sprintf(":%d", profilePort), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
restart:
|
||||
switch mode {
|
||||
case "client":
|
||||
log.Info("Starting relay agent client")
|
||||
utils.Mode = utils.RELAYAGENT
|
||||
go agent.RunRelayKubeCTLAgent(ctx, logLevel)
|
||||
case "cdclient":
|
||||
log.Info("Starting relay agent client")
|
||||
utils.Mode = utils.CDRELAYAGENT
|
||||
go agent.RunRelayCDAgent(ctx, logLevel)
|
||||
case "tail":
|
||||
log.Info("Starting relay log tail")
|
||||
go tail.RunRelayTail(ctx)
|
||||
case "cdrelay":
|
||||
utils.Mode = utils.CDRELAY
|
||||
log.Info("Starting cdrelay server")
|
||||
go relay.RunCDRelayServer(ctx, logLevel)
|
||||
default:
|
||||
// default server
|
||||
utils.Mode = utils.RELAY
|
||||
log.Info("Starting relay server")
|
||||
go relay.RunRelayServer(ctx, logLevel)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-utils.ExitChan:
|
||||
log.Info(
|
||||
"got exit",
|
||||
)
|
||||
time.Sleep(time.Second * 5)
|
||||
goto restart
|
||||
case <-utils.TerminateChan:
|
||||
terminate(cancel)
|
||||
case sig := <-signalChan:
|
||||
signalHandler(sig, cancel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,595 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/controller/apply"
|
||||
clientutil "github.com/RafaySystems/rcloud-base/components/common/pkg/controller/client"
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/sentry/register"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/cleanup"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/proxy"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/tunnel"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/viper"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
const (
|
||||
podNameEnv = "POD_NAME"
|
||||
podNamespaceEnv = "POD_NAMESPACE"
|
||||
maxDialsEnv = "MAX_DIALS"
|
||||
dialoutProxyEnv = "DIALOUT_PROXY"
|
||||
dialoutProxyAuthEnv = "DIALOUT_PROXY_AUTHENTICATION" // user:password
|
||||
configNameEnv = "RELAY_CONFIGMAP_NAME"
|
||||
configNameCD = "cd-agent-configmap"
|
||||
cdConfigPath = "/etc/config/relayConfigData"
|
||||
relayRegisterTokenName = "relays"
|
||||
relayClusterIDName = "clusterID"
|
||||
relayAgentIDName = "agentID"
|
||||
)
|
||||
|
||||
var (
|
||||
podName string
|
||||
podNamespace string
|
||||
relayRegisterToken string
|
||||
relayClusterID string
|
||||
relayAgentID string
|
||||
applier client.Client
|
||||
lastHash string
|
||||
log *relaylogger.RelayLog
|
||||
configName string
|
||||
)
|
||||
|
||||
const (
|
||||
rafaySystemNamespace = "rafay-system"
|
||||
)
|
||||
|
||||
func processRelayConfigData(cfgData string) error {
|
||||
if err := json.Unmarshal([]byte(cfgData), &utils.RelayNetworks); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to unmashal",
|
||||
)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getConfigMap(ctx context.Context, c client.Client, name string) (*corev1.ConfigMap, error) {
|
||||
cm := corev1.ConfigMap{}
|
||||
|
||||
err := c.Get(ctx, client.ObjectKey{
|
||||
Namespace: rafaySystemNamespace,
|
||||
Name: name,
|
||||
}, &cm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cm.TypeMeta = metav1.TypeMeta{
|
||||
Kind: "ConfigMap",
|
||||
APIVersion: "v1",
|
||||
}
|
||||
|
||||
return &cm, nil
|
||||
}
|
||||
|
||||
func getConfigHash(ctx context.Context, configMap string) (string, error) {
|
||||
|
||||
cm, err := getConfigMap(ctx, applier, configMap)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(cm.Data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
h.Write(b)
|
||||
|
||||
//return cm.Annotations[hash.ObjectHash], nil
|
||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func getRelayAgentConfig(ctx context.Context) error {
|
||||
var ok bool
|
||||
|
||||
cm, err := getConfigMap(ctx, applier, configName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if relayClusterID, ok = cm.Data[relayClusterIDName]; !ok {
|
||||
return fmt.Errorf("failed to get relayClusterID")
|
||||
}
|
||||
if relayRegisterToken, ok = cm.Data[relayRegisterTokenName]; !ok {
|
||||
return fmt.Errorf("failed to get relayRegisterToken")
|
||||
}
|
||||
|
||||
if err := processRelayConfigData(relayRegisterToken); err != nil {
|
||||
return fmt.Errorf("failed to process relayRegisterToken %s", relayRegisterToken)
|
||||
}
|
||||
if len(utils.RelayNetworks) <= 0 {
|
||||
return fmt.Errorf("empty relaynetwork configmap %s", relayRegisterToken)
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"relay agent config values",
|
||||
"podName", podName,
|
||||
"podNamespace", podNamespace,
|
||||
)
|
||||
|
||||
for _, item := range utils.RelayNetworks {
|
||||
log.Info(
|
||||
"relay network info",
|
||||
"Token", item.Token,
|
||||
"Addr", item.Addr,
|
||||
"Domain", item.Domain,
|
||||
"Name", item.Name,
|
||||
)
|
||||
}
|
||||
|
||||
utils.ClusterID = relayClusterID
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupclient(ctx context.Context, log *relaylogger.RelayLog) error {
|
||||
configName = "relay-agent-config"
|
||||
viper.SetDefault(podNameEnv, "relay-agent")
|
||||
viper.SetDefault(podNamespaceEnv, "rafay-system")
|
||||
viper.BindEnv(podNameEnv)
|
||||
viper.BindEnv(podNamespaceEnv)
|
||||
|
||||
podName = viper.GetString(podNameEnv)
|
||||
podNamespace = viper.GetString(podNamespaceEnv)
|
||||
|
||||
utils.PODNAME = podName
|
||||
|
||||
viper.SetDefault(maxDialsEnv, "10")
|
||||
viper.BindEnv(maxDialsEnv)
|
||||
utils.MaxDials = viper.GetInt(maxDialsEnv)
|
||||
|
||||
viper.SetDefault(dialoutProxyEnv, "")
|
||||
viper.BindEnv(dialoutProxyEnv)
|
||||
|
||||
if u, err := url.Parse(viper.GetString(dialoutProxyEnv)); err == nil {
|
||||
utils.DialoutProxy = u.Host
|
||||
} else {
|
||||
utils.DialoutProxy = viper.GetString(dialoutProxyEnv)
|
||||
}
|
||||
|
||||
viper.SetDefault(dialoutProxyAuthEnv, "")
|
||||
viper.BindEnv(dialoutProxyAuthEnv)
|
||||
proxyAuth := viper.GetString(dialoutProxyAuthEnv)
|
||||
utils.DialoutProxyAuth = proxyAuth
|
||||
|
||||
if utils.MaxDials < utils.MinDials {
|
||||
utils.MaxDials = utils.MinDials
|
||||
}
|
||||
|
||||
viper.SetDefault(configNameEnv, "")
|
||||
viper.BindEnv(configNameEnv)
|
||||
customeRelayCfgMap := viper.GetString(configNameEnv)
|
||||
if customeRelayCfgMap != "" {
|
||||
configName = customeRelayCfgMap
|
||||
}
|
||||
|
||||
err := getRelayAgentConfig(ctx)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to get relay config",
|
||||
)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupCDClient(ctx context.Context, log *relaylogger.RelayLog) error {
|
||||
|
||||
viper.SetDefault(podNameEnv, "relay-cdagent")
|
||||
viper.SetDefault(podNamespaceEnv, "rafay-system")
|
||||
viper.BindEnv(podNameEnv)
|
||||
viper.BindEnv(podNamespaceEnv)
|
||||
|
||||
podName = viper.GetString(podNameEnv)
|
||||
podNamespace = viper.GetString(podNamespaceEnv)
|
||||
|
||||
utils.PODNAME = podName
|
||||
|
||||
viper.SetDefault(maxDialsEnv, "2")
|
||||
viper.BindEnv(maxDialsEnv)
|
||||
// utils.MaxDials = viper.GetInt(maxDialsEnv)
|
||||
|
||||
viper.SetDefault(dialoutProxyEnv, "")
|
||||
viper.BindEnv(dialoutProxyEnv)
|
||||
// utils.DialoutProxy = viper.GetString(dialoutProxyEnv)
|
||||
|
||||
viper.SetDefault(dialoutProxyAuthEnv, "")
|
||||
viper.BindEnv(dialoutProxyAuthEnv)
|
||||
// proxyAuth := viper.GetString(dialoutProxyAuthEnv)
|
||||
// utils.DialoutProxyAuth = base64.StdEncoding.EncodeToString([]byte(proxyAuth))
|
||||
|
||||
// if utils.MaxDials < 1 {
|
||||
// utils.MaxDials = 2
|
||||
// }
|
||||
|
||||
err := getRelayCDAgentConfig(ctx)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to get relay config",
|
||||
)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRelayCDAgentConfig(ctx context.Context) error {
|
||||
var ok bool
|
||||
|
||||
configBytes, err := ioutil.ReadFile(cdConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var config map[string]interface{}
|
||||
err = json.Unmarshal(configBytes, &config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if relayAgentID, ok = config[relayAgentIDName].(string); !ok {
|
||||
return fmt.Errorf("failed to get cd-relayClusterID")
|
||||
}
|
||||
|
||||
if maxDialsStr, ok := config["maxDials"].(string); ok {
|
||||
maxDials, err := strconv.Atoi(maxDialsStr)
|
||||
if err != nil {
|
||||
maxDials = 2
|
||||
}
|
||||
utils.MaxDials = maxDials
|
||||
}
|
||||
|
||||
if utils.MaxDials < utils.MinDials {
|
||||
utils.MaxDials = utils.MinDials
|
||||
}
|
||||
|
||||
var dialoutProxy string
|
||||
if dp, ok := config["dialoutProxy"]; ok {
|
||||
if dialoutProxy, ok = dp.(string); ok {
|
||||
}
|
||||
}
|
||||
|
||||
if dialoutProxy == "" {
|
||||
if u, err := url.Parse(viper.GetString(dialoutProxyEnv)); err == nil {
|
||||
dialoutProxy = u.Host
|
||||
} else {
|
||||
dialoutProxy = viper.GetString(dialoutProxyEnv)
|
||||
}
|
||||
}
|
||||
|
||||
utils.DialoutProxy = dialoutProxy
|
||||
|
||||
var dialoutProxyAuth string
|
||||
if dpa, ok := config["dialoutProxyAuthentication"]; ok {
|
||||
if dialoutProxyAuth, ok = dpa.(string); ok {
|
||||
}
|
||||
}
|
||||
|
||||
if dialoutProxyAuth == "" {
|
||||
dialoutProxyAuth = viper.GetString(dialoutProxyAuthEnv)
|
||||
}
|
||||
|
||||
utils.DialoutProxyAuth = dialoutProxyAuth
|
||||
|
||||
if relays, ok := config[relayRegisterTokenName].(interface{}); ok {
|
||||
relayRegisterTokenBytes, err := json.Marshal(relays)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get cd-relayRegisterToken: %s", err.Error())
|
||||
}
|
||||
relayRegisterToken = string(relayRegisterTokenBytes)
|
||||
} else {
|
||||
return fmt.Errorf("failed to get cd-relayRegisterToken")
|
||||
}
|
||||
|
||||
if err := processRelayConfigData(relayRegisterToken); err != nil {
|
||||
return fmt.Errorf("failed to process cd-relayRegisterToken %s", relayRegisterToken)
|
||||
}
|
||||
if len(utils.RelayNetworks) <= 0 {
|
||||
return fmt.Errorf("empty cd-relaynetwork configmap %s", relayRegisterToken)
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"relay cd agent config values",
|
||||
"podName", podName,
|
||||
"podNamespace", podNamespace,
|
||||
)
|
||||
|
||||
for _, item := range utils.RelayNetworks {
|
||||
log.Info(
|
||||
"relay network info",
|
||||
"Token", item.Token,
|
||||
"Addr", item.Addr,
|
||||
"Domain", item.Domain,
|
||||
"Name", item.Name,
|
||||
)
|
||||
}
|
||||
|
||||
utils.AgentID = relayAgentID
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerRelayAgent will register with rafay-core-relay-connector template token
|
||||
// registration fetches client-certificate/root-ca to connect to relay server
|
||||
func registerRelayAgent(ctx context.Context, rn utils.Relaynetwork) error {
|
||||
cfg := ®ister.Config{
|
||||
TemplateToken: rn.TemplateToken,
|
||||
Addr: rn.Addr,
|
||||
ClientID: rn.Token,
|
||||
ClientIP: utils.GetRelayIP(),
|
||||
Name: podName,
|
||||
}
|
||||
|
||||
if utils.IsHTTPS(rn.Addr) {
|
||||
cfg.Scheme = "https"
|
||||
}
|
||||
|
||||
log.Info("config:", cfg)
|
||||
|
||||
if err := register.Register(ctx, cfg); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register relay agent",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"certificate:",
|
||||
string(cfg.Certificate),
|
||||
)
|
||||
|
||||
rc := utils.RelayNetworkConfig{}
|
||||
rc.Network = rn
|
||||
rc.RelayAgentCACert = cfg.CACertificate
|
||||
rc.RelayAgentCert = cfg.Certificate
|
||||
rc.RelayAgentKey = cfg.PrivateKey
|
||||
|
||||
utils.RelayAgentConfig[rn.Name] = rc
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkConfigMapChange(configMap string) bool {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
|
||||
h, err := getConfigHash(ctx, configMap)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to get relay configmap hash",
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if lastHash != "" {
|
||||
if lastHash != h {
|
||||
//hash changed
|
||||
log.Info("hash of configmap data changed", "prev", lastHash, "curr", h)
|
||||
lastHash = h
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
log.Info("setting hash of configmap data", "hash", h)
|
||||
lastHash = h
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// RunRelayCDAgent entry to the relay client
|
||||
func RunRelayCDAgent(ctx context.Context, logLvl int) {
|
||||
lastHash = ""
|
||||
utils.RelayNetworks = nil
|
||||
utils.RelayAgentConfig = make(map[string]utils.RelayNetworkConfig)
|
||||
|
||||
log = relaylogger.NewLogger(logLvl).WithName("Relay Agent")
|
||||
|
||||
c, err := clientutil.New()
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed in clientutil new",
|
||||
)
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
if err := proxy.InitUnixCacheRoundTripper(); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to init unix cached round tripper",
|
||||
)
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
applier = apply.NewApplier(c)
|
||||
|
||||
rctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := setupCDClient(rctx, log); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"relay agent exiting",
|
||||
)
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
for _, rn := range utils.RelayNetworks {
|
||||
go handleRelayNetworks(rctx, rn)
|
||||
}
|
||||
|
||||
//watch config changes
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Error(err, "unable to create watcher for config file")
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
defer watcher.Close()
|
||||
err = watcher.Add(cdConfigPath)
|
||||
if err != nil {
|
||||
log.Error(err, "unable to add config file to watcher")
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if ok {
|
||||
log.Info("event:", event, "modified file:", event.Name)
|
||||
}
|
||||
if event.Op != fsnotify.Chmod {
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
log.Info("error:", err)
|
||||
case <-ctx.Done():
|
||||
log.Info(
|
||||
"Relay agent exiting",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RunRelayKubeCTLAgent entry to the relay client
|
||||
func RunRelayKubeCTLAgent(ctx context.Context, logLvl int) {
|
||||
lastHash = ""
|
||||
utils.RelayNetworks = nil
|
||||
utils.RelayAgentConfig = make(map[string]utils.RelayNetworkConfig)
|
||||
|
||||
log = relaylogger.NewLogger(logLvl).WithName("Relay Agent")
|
||||
|
||||
c, err := clientutil.New()
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed in clientutil new",
|
||||
)
|
||||
utils.TerminateChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
if err := proxy.InitUnixCacheRoundTripper(); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to init unix cached round tripper",
|
||||
)
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
applier = apply.NewApplier(c)
|
||||
|
||||
rctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := setupclient(rctx, log); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"relay agent exiting",
|
||||
)
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
go cleanup.StaleAuthz(rctx)
|
||||
|
||||
for _, rn := range utils.RelayNetworks {
|
||||
go handleRelayNetworks(rctx, rn)
|
||||
}
|
||||
|
||||
//ticker configmap changes
|
||||
ticker := time.NewTicker(10 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
if checkConfigMapChange(configName) {
|
||||
// cancel the ctx
|
||||
ticker.Stop()
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
log.Info(
|
||||
"Relay agent exiting",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func handleRelayNetworks(ctx context.Context, rn utils.Relaynetwork) {
|
||||
rnExitChan := make(chan bool)
|
||||
restartRegister:
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
if err := registerRelayAgent(ctx, rn); err != nil {
|
||||
//wait until config is available
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
goto restartRegister
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
ticker.Stop()
|
||||
|
||||
restartNetwork:
|
||||
go tunnel.StartClient(ctx, log, "", utils.RelayAgentConfig[rn.Name], rnExitChan)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-rnExitChan:
|
||||
log.Info(
|
||||
"relay network stopped, restart in 5 secs",
|
||||
"name", rn.Name,
|
||||
)
|
||||
time.Sleep(2 * time.Second)
|
||||
goto restartNetwork
|
||||
case <-ctx.Done():
|
||||
log.Info(
|
||||
"Relay network exiting",
|
||||
"name", rn.Name,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
)
|
||||
|
||||
// RunCDAgentRoutine starts cd agent. run as a go routine
|
||||
func RunCDAgentRoutine(ctx context.Context, logLevel int) {
|
||||
|
||||
_log := relaylogger.NewLogger(logLevel).WithName("Relay")
|
||||
_log.Info("Starting relay agent client")
|
||||
|
||||
utils.GenUUID()
|
||||
utils.LogLevel = logLevel
|
||||
utils.Mode = utils.CDRELAYAGENT
|
||||
|
||||
restart:
|
||||
go RunRelayCDAgent(ctx, logLevel)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-utils.ExitChan:
|
||||
log.Info(
|
||||
"got exit",
|
||||
)
|
||||
time.Sleep(time.Second * 5)
|
||||
goto restart
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package audit
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/sessions"
|
||||
"github.com/felixge/httpsnoop"
|
||||
"github.com/rs/xid"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// options holds audit options
|
||||
type options struct {
|
||||
basePath string
|
||||
maxSizeMB int
|
||||
maxBackups int
|
||||
maxAgeDays int
|
||||
}
|
||||
|
||||
// Option is the functional argument for audit options
|
||||
type Option func(o *options)
|
||||
|
||||
// WithBasePath sets base path for audit logs
|
||||
func WithBasePath(path string) Option {
|
||||
return func(o *options) {
|
||||
o.basePath = path
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxSizeMB sets max size of audit file before it is rotated
|
||||
func WithMaxSizeMB(size int) Option {
|
||||
return func(o *options) {
|
||||
o.maxSizeMB = size
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxBackups sets maximum number of backed up rotated audit logs to maintain
|
||||
func WithMaxBackups(backups int) Option {
|
||||
return func(o *options) {
|
||||
o.maxBackups = backups
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxAgeDays sets age after which backed up rotated audit logs will be deleted
|
||||
func WithMaxAgeDays(ageDays int) Option {
|
||||
return func(o *options) {
|
||||
o.maxAgeDays = ageDays
|
||||
}
|
||||
}
|
||||
|
||||
type audit struct {
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func (a *audit) handler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
metrics := httpsnoop.CaptureMetrics(next, w, r)
|
||||
|
||||
fields := make([]zapcore.Field, 0, 10)
|
||||
fields = append(fields, zap.String("xid", xid.New().String()))
|
||||
fields = append(fields, zap.String("method", r.Method))
|
||||
fields = append(fields, zap.String("url", r.URL.EscapedPath()))
|
||||
fields = append(fields, zap.String("query", r.URL.RawQuery))
|
||||
fields = append(fields, zap.String("serverName", r.TLS.ServerName))
|
||||
fields = append(fields, zap.String("user", r.TLS.PeerCertificates[0].Subject.CommonName))
|
||||
fields = append(fields, zap.String("remoteAddr", strings.Split(r.RemoteAddr, ":")[0]))
|
||||
fields = append(fields, zap.Int("statusCode", metrics.Code))
|
||||
fields = append(fields, zap.Int64("written", metrics.Written))
|
||||
fields = append(fields, zap.Duration("duration", metrics.Duration))
|
||||
if r.Header.Get("X-Rafay-Audit") == "" {
|
||||
a.logger.Info("access", fields...)
|
||||
} else {
|
||||
a.logger.Info("audit", fields...)
|
||||
}
|
||||
|
||||
if metrics.Code == http.StatusUnauthorized || metrics.Code == http.StatusBadGateway {
|
||||
sessKey := r.Header.Get("X-Rafay-Sessionkey")
|
||||
sessions.SetSessionErrorFlag(sessKey)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// WrapWithAudit wrap audit handler around next http.Handler
|
||||
func WrapWithAudit(next http.Handler, opts ...Option) http.Handler {
|
||||
|
||||
auditOpts := &options{}
|
||||
for _, opt := range opts {
|
||||
opt(auditOpts)
|
||||
}
|
||||
|
||||
audit := &audit{logger: getAuditLogger(auditOpts)}
|
||||
return audit.handler(next)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package audit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
func getAuditLogger(opts *options) *zap.Logger {
|
||||
|
||||
path := fmt.Sprintf("%s/audit.log", opts.basePath)
|
||||
|
||||
encoder := zap.NewProductionEncoderConfig()
|
||||
encoder.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
|
||||
logger := zap.New(zapcore.NewCore(
|
||||
zapcore.NewJSONEncoder(encoder),
|
||||
zapcore.AddSync(&lumberjack.Logger{
|
||||
Filename: path,
|
||||
MaxSize: opts.maxSizeMB, // megabytes
|
||||
MaxBackups: opts.maxBackups,
|
||||
MaxAge: opts.maxAgeDays, // days
|
||||
}),
|
||||
zap.InfoLevel,
|
||||
))
|
||||
|
||||
return logger
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package cleanup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
clientutil "github.com/RafaySystems/rcloud-base/components/common/pkg/controller/client"
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
)
|
||||
|
||||
var (
|
||||
_log = log.GetLogger()
|
||||
)
|
||||
|
||||
const (
|
||||
// how often should the cleanup routine run
|
||||
sweepInterval = time.Minute * 10
|
||||
// any authz which is olderThan this should be cleaned up
|
||||
olderThan = time.Hour * 8
|
||||
|
||||
rafayRelayLabel = "rafay-relay"
|
||||
authzRefreshLabel = "authz-refreshed"
|
||||
rafaySystemNS = "rafay-system"
|
||||
|
||||
maxResults = 50
|
||||
)
|
||||
|
||||
func getMatchingLabelSelector() (sel client.MatchingLabelsSelector, err error) {
|
||||
var relayLabelReq, refreshLabelReq *labels.Requirement
|
||||
|
||||
relayLabelReq, err = labels.NewRequirement(rafayRelayLabel, selection.Equals, []string{"true"})
|
||||
if err != nil {
|
||||
_log.Infow("unable to create relay label requirment", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
refreshLabelReq, err = labels.NewRequirement(
|
||||
authzRefreshLabel,
|
||||
selection.LessThan,
|
||||
[]string{strconv.FormatInt(time.Now().Add(-olderThan).Unix(), 10)},
|
||||
)
|
||||
if err != nil {
|
||||
_log.Infow("unable to create authz refresh requirment", "error", err)
|
||||
return
|
||||
}
|
||||
sel.Selector = labels.NewSelector().Add(*relayLabelReq, *refreshLabelReq)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func cleanServiceAccounts(ctx context.Context, c client.Client, sel client.MatchingLabelsSelector) {
|
||||
nCtx, cancel := context.WithTimeout(ctx, time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
var saList corev1.ServiceAccountList
|
||||
|
||||
err := c.List(nCtx, &saList, sel, client.InNamespace(rafaySystemNS), client.Limit(maxResults))
|
||||
if err != nil {
|
||||
_log.Infow("unable to list service accounts", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range saList.Items {
|
||||
_log.Infow("found stale service account", "name", item.Name)
|
||||
err = c.Delete(ctx, &item)
|
||||
if err != nil {
|
||||
_log.Infow("unable to delete stale service account", "name", item.Name, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func cleanClusterRoleBindings(ctx context.Context, c client.Client, sel client.MatchingLabelsSelector) {
|
||||
nCtx, cancel := context.WithTimeout(ctx, time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
var crbList rbacv1.ClusterRoleBindingList
|
||||
|
||||
err := c.List(nCtx, &crbList, sel, client.Limit(maxResults))
|
||||
if err != nil {
|
||||
_log.Infow("unable to list cluster role bindings", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range crbList.Items {
|
||||
_log.Infow("found stale cluster role binding", "name", item.Name)
|
||||
err = c.Delete(ctx, &item)
|
||||
if err != nil {
|
||||
_log.Infow("unable to delete cluster role binding", "name", item.Name, "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cleanRoleBindings(ctx context.Context, c client.Client, sel client.MatchingLabelsSelector) {
|
||||
nCtx, cancel := context.WithTimeout(ctx, time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
var rbList rbacv1.RoleBindingList
|
||||
|
||||
err := c.List(nCtx, &rbList, sel, client.Limit(maxResults))
|
||||
if err != nil {
|
||||
_log.Infow("unable to list role bindings", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range rbList.Items {
|
||||
_log.Infow("found stale role binding", "name", item.Name)
|
||||
err = c.Delete(ctx, &item)
|
||||
if err != nil {
|
||||
_log.Infow("unable to delete role binding", "name", item.Name, "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StaleAuthz cleans up state authorizations provisioned in the cluster
|
||||
func StaleAuthz(ctx context.Context) {
|
||||
c, err := clientutil.New()
|
||||
if err != nil {
|
||||
_log.Fatalw("unable to create client for cleaning stale authz entries", "error", err)
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(sweepInterval)
|
||||
sweepLoop:
|
||||
for ; true; <-ticker.C {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break sweepLoop
|
||||
default:
|
||||
}
|
||||
|
||||
sel, err := getMatchingLabelSelector()
|
||||
if err != nil {
|
||||
_log.Infow("unable to build matching label selector", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
_log.Infow("finding authz matching", "selector", sel)
|
||||
|
||||
cleanClusterRoleBindings(ctx, c, sel)
|
||||
cleanRoleBindings(ctx, c, sel)
|
||||
cleanServiceAccounts(ctx, c, sel)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RunProfiler runs pprof on the given port
|
||||
func RunProfiler(port int, stop <-chan struct{}) error {
|
||||
|
||||
s := http.Server{
|
||||
Addr: fmt.Sprintf(":%d", port),
|
||||
}
|
||||
|
||||
defer func() {
|
||||
<-stop
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
s.Shutdown(ctx)
|
||||
}()
|
||||
|
||||
err := s.ListenAndServe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"hash"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
"github.com/dgraph-io/ristretto"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
k8proxy "k8s.io/apimachinery/pkg/util/proxy"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/transport"
|
||||
)
|
||||
|
||||
// TODO convert to JSON
|
||||
type responder struct{}
|
||||
|
||||
func (r *responder) Error(w http.ResponseWriter, req *http.Request, err error) {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
type unixCachedRoundTrip struct {
|
||||
proxy http.Handler
|
||||
t *http.Transport
|
||||
}
|
||||
|
||||
type relayCachedPeerRoundTrip struct {
|
||||
proxy http.Handler
|
||||
t *http.Transport
|
||||
}
|
||||
|
||||
var (
|
||||
cacheTTL = time.Minute * 15
|
||||
// cache map of unix round tripper
|
||||
unixCachedRoundTripper *ristretto.Cache
|
||||
// cache map for peer upstream round tripper
|
||||
relayPeerRoundTripper *ristretto.Cache
|
||||
)
|
||||
|
||||
// InitUnixCacheRoundTripper initialize the cache
|
||||
func InitUnixCacheRoundTripper() error {
|
||||
var err error
|
||||
unixCachedRoundTripper, err = ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1e4, // Num keys to track frequency of (10k).
|
||||
MaxCost: 1 << 25, // Maximum cost of cache (32MB).
|
||||
BufferItems: 64, // Number of keys per Get buffer.
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// InitPeerCacheRoundTripper initialize the cache
|
||||
func InitPeerCacheRoundTripper() error {
|
||||
var err error
|
||||
relayPeerRoundTripper, err = ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1e4, // Num keys to track frequency of (10k).
|
||||
MaxCost: 1 << 25, // Maximum cost of cache (32MB).
|
||||
BufferItems: 64, // Number of keys per Get buffer.
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// makeUpgradeTransport creates a transport that explicitly bypasses HTTP2 support
|
||||
// for proxy connections that must upgrade.
|
||||
func makeUpgradeTransport(config *rest.Config, keepalive time.Duration) (k8proxy.UpgradeRequestRoundTripper, error) {
|
||||
|
||||
transportConfig, err := config.TransportConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig, err := transport.TLSConfigFor(transportConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.NextProtos = []string{"http/1.1"}
|
||||
rt := utilnet.SetOldTransportDefaults(&http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: keepalive,
|
||||
}).DialContext,
|
||||
TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
|
||||
MaxIdleConns: idleConns,
|
||||
MaxConnsPerHost: idleConnsPerHost,
|
||||
})
|
||||
|
||||
upgrader, err := transport.HTTPWrappersForConfig(transportConfig, k8proxy.MirrorRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return k8proxy.NewUpgradeRequestRoundTripper(rt, upgrader), nil
|
||||
}
|
||||
|
||||
// NewCachedKubeHandler is cached kube handler
|
||||
func NewCachedKubeHandler(cfg *rest.Config, keepalive time.Duration) (*k8proxy.UpgradeAwareHandler, error) {
|
||||
host := cfg.Host
|
||||
if !strings.HasSuffix(host, "/") {
|
||||
host = host + "/"
|
||||
}
|
||||
target, err := url.Parse(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responder := &responder{}
|
||||
|
||||
transport, err := rest.TransportFor(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rt, err := NewCachedRoundTripper(transport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
upgradeTransport, err := makeUpgradeTransport(cfg, keepalive)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kproxy := k8proxy.NewUpgradeAwareHandler(target, rt, false, false, responder)
|
||||
kproxy.UpgradeTransport = upgradeTransport
|
||||
kproxy.UseRequestLocation = true
|
||||
|
||||
return kproxy, nil
|
||||
}
|
||||
|
||||
// UnixDialContext unix dial
|
||||
func UnixDialContext(sockPath, key, username, sni string) func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
|
||||
conn, err := net.DialTimeout("unix", sockPath, 60*time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hdr := &utils.ProxyProtocolMessage{
|
||||
DialinKey: key,
|
||||
UserName: username,
|
||||
SNI: sni,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(hdr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := make([]byte, utils.ProxyProtocolSize)
|
||||
copy(buf, b)
|
||||
|
||||
_, err = conn.Write(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
}
|
||||
|
||||
func makeUnixUpgradeTransport(sockPath, key, username, sni string) (k8proxy.UpgradeRequestRoundTripper, error) {
|
||||
|
||||
rt := utilnet.SetOldTransportDefaults(&http.Transport{
|
||||
DialContext: UnixDialContext(sockPath, key, username, sni),
|
||||
})
|
||||
|
||||
upgrader, err := transport.HTTPWrappersForConfig(new(transport.Config), k8proxy.MirrorRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return k8proxy.NewUpgradeRequestRoundTripper(rt, upgrader), nil
|
||||
}
|
||||
|
||||
func getRTCacheKey(skey string) (key uint64) {
|
||||
hasher := _hashPool.Get().(hash.Hash64)
|
||||
hasher.Reset()
|
||||
hasher.Write([]byte(skey))
|
||||
key = hasher.Sum64()
|
||||
_hashPool.Put(hasher)
|
||||
return
|
||||
}
|
||||
|
||||
type unixHandlerOptions struct {
|
||||
sockPath string
|
||||
key string
|
||||
username string
|
||||
sni string
|
||||
}
|
||||
|
||||
//UnixKubeHandler unix handler
|
||||
func UnixKubeHandler(sockPath, key, username, sni string) (http.Handler, error) {
|
||||
|
||||
hkey := getRTCacheKey(username + key)
|
||||
if val, ok := unixCachedRoundTripper.Get(hkey); ok {
|
||||
rt := val.(unixCachedRoundTrip)
|
||||
return rt.proxy, nil
|
||||
}
|
||||
|
||||
target, err := url.Parse("http://unixpath-relay/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responder := &responder{}
|
||||
|
||||
upgradeTransport, err := makeUnixUpgradeTransport(sockPath, key, username, sni)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := getUnixTransport(sockPath, key, username, sni)
|
||||
proxy := k8proxy.NewUpgradeAwareHandler(target, t, false, false, responder)
|
||||
proxy.UpgradeTransport = upgradeTransport
|
||||
proxy.UseRequestLocation = true
|
||||
|
||||
rt := unixCachedRoundTrip{
|
||||
proxy: proxy,
|
||||
t: t,
|
||||
}
|
||||
|
||||
unixCachedRoundTripper.SetWithTTL(hkey, rt, 100, cacheTTL)
|
||||
|
||||
return proxy, nil
|
||||
}
|
||||
|
||||
// Peer Relay Proxy Helpers
|
||||
func peerDialContext(relayIP string) func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
conn, err := net.DialTimeout("tcp", relayIP, 60*time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
}
|
||||
|
||||
//makePeerUpgradeTransport ...
|
||||
func makePeerUpgradeTransport(relayIP string, tlscfg *tls.Config) (k8proxy.UpgradeRequestRoundTripper, error) {
|
||||
rt := utilnet.SetOldTransportDefaults(&http.Transport{
|
||||
DialContext: peerDialContext(relayIP),
|
||||
TLSClientConfig: tlscfg,
|
||||
MaxIdleConns: 10,
|
||||
IdleConnTimeout: utils.IdleTimeout,
|
||||
TLSHandshakeTimeout: 30 * time.Second,
|
||||
// Keep the peer upstream non http2
|
||||
// Found issues in upgradeaware http2
|
||||
// missing http2 preface when doing proxy.
|
||||
ForceAttemptHTTP2: false,
|
||||
})
|
||||
|
||||
upgrader, err := transport.HTTPWrappersForConfig(new(transport.Config), k8proxy.MirrorRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return k8proxy.NewUpgradeRequestRoundTripper(rt, upgrader), nil
|
||||
}
|
||||
|
||||
//PeerKubeHandler peer proxying handler
|
||||
func PeerKubeHandler(tlscfg *tls.Config, relayIP string) (http.Handler, error) {
|
||||
hkey := getRTCacheKey(tlscfg.ServerName)
|
||||
if val, ok := relayPeerRoundTripper.Get(hkey); ok {
|
||||
rt := val.(relayCachedPeerRoundTrip)
|
||||
return rt.proxy, nil
|
||||
}
|
||||
|
||||
target, err := url.Parse("https://" + tlscfg.ServerName + "/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responder := &responder{}
|
||||
|
||||
upgradeTransport, err := makePeerUpgradeTransport(relayIP, tlscfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := getPeerTransport(tlscfg, relayIP)
|
||||
proxy := k8proxy.NewUpgradeAwareHandler(target, t, false, false, responder)
|
||||
proxy.UpgradeTransport = upgradeTransport
|
||||
proxy.UseRequestLocation = true
|
||||
|
||||
rt := relayCachedPeerRoundTrip{
|
||||
proxy: proxy,
|
||||
t: t,
|
||||
}
|
||||
|
||||
relayPeerRoundTripper.SetWithTTL(hkey, rt, 100, cacheTTL)
|
||||
|
||||
return proxy, nil
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
)
|
||||
|
||||
// Func is responsible for forwarding a remote connection to local server
|
||||
// and writing the response.
|
||||
type Func func(w io.Writer, r io.ReadCloser, msg *utils.ControlMessage, req *http.Request)
|
||||
@@ -0,0 +1,214 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/twmb/murmur3"
|
||||
|
||||
clientutil "github.com/RafaySystems/rcloud-base/components/common/pkg/controller/client"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
"github.com/dgraph-io/ristretto"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var (
|
||||
logger = relaylogger.NewLogger(utils.LogLevel).WithName("Proxy")
|
||||
// ErrInvalidUser is returned for invalid user
|
||||
ErrInvalidUser = errors.New("invalid user")
|
||||
)
|
||||
|
||||
var _hashPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
// The Pool's New function should generally only return pointer
|
||||
// types, since a pointer can be put into the return interface
|
||||
// value without an allocation:
|
||||
return murmur3.New64()
|
||||
},
|
||||
}
|
||||
|
||||
const (
|
||||
defaulTLSHandshakeTimeout = 10 * time.Second
|
||||
idleConnsPerHost = 5
|
||||
idleConns = 25
|
||||
defaultTimeout = 30 * time.Second
|
||||
defaultKeepAlive = 30 * time.Second
|
||||
disableCompression = false
|
||||
)
|
||||
|
||||
func getUnixTransport(sockPath, key, username, sni string) *http.Transport {
|
||||
return utilnet.SetTransportDefaults(&http.Transport{
|
||||
TLSHandshakeTimeout: defaulTLSHandshakeTimeout,
|
||||
MaxIdleConnsPerHost: idleConnsPerHost,
|
||||
DialContext: UnixDialContext(sockPath, key, username, sni),
|
||||
DisableCompression: disableCompression,
|
||||
MaxIdleConns: idleConns,
|
||||
})
|
||||
}
|
||||
|
||||
func getPeerTransport(tlscfg *tls.Config, relayIP string) *http.Transport {
|
||||
if tlscfg != nil {
|
||||
tlscfg.NextProtos = []string{"http/1.1"}
|
||||
}
|
||||
return &http.Transport{
|
||||
TLSHandshakeTimeout: defaulTLSHandshakeTimeout,
|
||||
TLSClientConfig: tlscfg,
|
||||
MaxIdleConns: idleConns,
|
||||
MaxIdleConnsPerHost: idleConnsPerHost,
|
||||
DialContext: peerDialContext(relayIP),
|
||||
DisableCompression: disableCompression,
|
||||
TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
|
||||
//Keep the peer upstream non http2
|
||||
ForceAttemptHTTP2: false,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCachedRoundTripper returns new cached round tripper
|
||||
func NewCachedRoundTripper(rt http.RoundTripper) (http.RoundTripper, error) {
|
||||
logger = relaylogger.NewLogger(utils.LogLevel).WithName("CachedRoundTripper")
|
||||
c, err := clientutil.New()
|
||||
if err != nil {
|
||||
logger.Error(
|
||||
err,
|
||||
"failed in clientutil.New",
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cache, err := ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1e4, // Num keys to track frequency of (10k).
|
||||
MaxCost: 1 << 25, // Maximum cost of cache (32MB).
|
||||
BufferItems: 64, // Number of keys per Get buffer.
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
crt := &cachedRoundTripper{client: c, cache: cache, rt: rt}
|
||||
|
||||
return crt, nil
|
||||
}
|
||||
|
||||
type cachedRoundTripper struct {
|
||||
client client.Client
|
||||
rt http.RoundTripper
|
||||
cache *ristretto.Cache
|
||||
}
|
||||
|
||||
func getCacheKey(userName, namespace string) (key uint64) {
|
||||
hasher := _hashPool.Get().(hash.Hash64)
|
||||
hasher.Reset()
|
||||
hasher.Write([]byte(namespace))
|
||||
hasher.Write([]byte(userName))
|
||||
key = hasher.Sum64()
|
||||
_hashPool.Put(hasher)
|
||||
return
|
||||
}
|
||||
|
||||
func (rt *cachedRoundTripper) getToken(req *http.Request) (token string, err error) {
|
||||
userName := req.Header.Get(utils.HeaderRafayUserName)
|
||||
namespace := req.Header.Get(utils.HeaderRafayNamespace)
|
||||
clearCache := req.Header.Get(utils.HeaderClearSecret)
|
||||
if userName == "" || namespace == "" {
|
||||
logger.Error(
|
||||
nil,
|
||||
"getToken failed",
|
||||
"userName", userName,
|
||||
"namespace", namespace,
|
||||
"req", req,
|
||||
)
|
||||
return "", ErrInvalidUser
|
||||
}
|
||||
|
||||
logger.Debug(
|
||||
"getToken for ",
|
||||
"user", userName,
|
||||
"namespace", namespace,
|
||||
"clearCache", clearCache,
|
||||
)
|
||||
|
||||
key := getCacheKey(userName, namespace)
|
||||
|
||||
if clearCache == "" {
|
||||
if val, ok := rt.cache.Get(key); ok {
|
||||
if strVal, ok := val.(string); ok {
|
||||
logger.Debug(
|
||||
"token found in cache ",
|
||||
"user", userName,
|
||||
"namespace", namespace,
|
||||
)
|
||||
token = strVal
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Clear the header
|
||||
req.Header.Del(utils.HeaderClearSecret)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(req.Context(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
secret, err := getServiceAccountSecret(ctx, rt.client, userName, namespace)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
token = string(secret.Data[tokenKey])
|
||||
rt.cache.SetWithTTL(key, token, 100, time.Minute*5)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (rt *cachedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
logger.Debug("RoundTrip", "request", req)
|
||||
// cache here
|
||||
token, err := rt.getToken(req)
|
||||
if err != nil {
|
||||
logger.Error(
|
||||
err,
|
||||
"failed getToken in RoundTrip",
|
||||
"req", req,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req = utilnet.CloneRequest(req)
|
||||
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||
// remove x-rafay heders before sending to kube-apiserver
|
||||
req.Header.Del("X-Rafay-Key")
|
||||
req.Header.Del("X-Rafay-Namespace")
|
||||
req.Header.Del("X-Rafay-User")
|
||||
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (rt *cachedRoundTripper) CancelRequest(req *http.Request) {
|
||||
tryCancelRequest(rt.WrappedRoundTripper(), req)
|
||||
}
|
||||
|
||||
func (rt *cachedRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
|
||||
|
||||
func tryCancelRequest(rt http.RoundTripper, req *http.Request) {
|
||||
type canceler interface {
|
||||
CancelRequest(*http.Request)
|
||||
}
|
||||
switch rt := rt.(type) {
|
||||
case canceler:
|
||||
rt.CancelRequest(req)
|
||||
case utilnet.RoundTripperWrapper:
|
||||
tryCancelRequest(rt.WrappedRoundTripper(), req)
|
||||
default:
|
||||
logger.Error(nil, "Unable to cancel request")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/controller/apply"
|
||||
clientutil "github.com/RafaySystems/rcloud-base/components/common/pkg/controller/client"
|
||||
cruntime "github.com/RafaySystems/rcloud-base/components/common/pkg/controller/runtime"
|
||||
clusterv2 "github.com/RafaySystems/rcloud-base/components/common/proto/types/controller"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
var (
|
||||
svclogger = relaylogger.NewLogger(utils.LogLevel).WithName("ServiceAccount")
|
||||
// ErrNotSAToken is returned when secret refered by service account is not of type service account token
|
||||
ErrNotSAToken = errors.New("secert is not of type ServiceAccountToken")
|
||||
)
|
||||
|
||||
const (
|
||||
caCertKey = "ca.crt"
|
||||
tokenKey = "token"
|
||||
)
|
||||
|
||||
// getServiceAccountSecret returns secret for the service account
|
||||
func getServiceAccountSecret(ctx context.Context, c k8sclient.Client, name, namespace string) (*corev1.Secret, error) {
|
||||
var serviceAccount corev1.ServiceAccount
|
||||
var secret corev1.Secret
|
||||
|
||||
err := c.Get(ctx, k8sclient.ObjectKey{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
}, &serviceAccount)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, saSecret := range serviceAccount.Secrets {
|
||||
err = c.Get(ctx, k8sclient.ObjectKey{
|
||||
Name: saSecret.Name,
|
||||
Namespace: namespace,
|
||||
}, &secret)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if secret.Type == corev1.SecretTypeServiceAccountToken {
|
||||
return &secret, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("service account %s/%s does not have secrets of type ServiceAccountToken", namespace, name)
|
||||
}
|
||||
|
||||
//DeleteServiceAccount from cluster and cache
|
||||
func DeleteServiceAccount(key, rafayAuthzSA, rafayAuthzRole, rafayAuthzRoleBind string, delCache bool) {
|
||||
svclogger.Debug(
|
||||
"DeleteServiceAccount",
|
||||
key,
|
||||
"not evicted", delCache,
|
||||
)
|
||||
dstrSA, err1 := base64.StdEncoding.DecodeString(rafayAuthzSA)
|
||||
dstrRole, err2 := base64.StdEncoding.DecodeString(rafayAuthzRole)
|
||||
dstrRB, err3 := base64.StdEncoding.DecodeString(rafayAuthzRoleBind)
|
||||
|
||||
if err1 == nil && err2 == nil && err3 == nil {
|
||||
// delete sa,role,rolebinding
|
||||
svclogger.Debug(
|
||||
"delete service account",
|
||||
"yaml SA:",
|
||||
string(dstrSA),
|
||||
"yaml Role:",
|
||||
string(dstrRole),
|
||||
"yaml RoleBind:",
|
||||
string(dstrRB),
|
||||
)
|
||||
|
||||
c, err := clientutil.New()
|
||||
if err != nil {
|
||||
svclogger.Error(
|
||||
err,
|
||||
"failed in clientutil new",
|
||||
)
|
||||
return
|
||||
}
|
||||
applier := apply.NewApplier(c)
|
||||
|
||||
sa, err1 := getObject(dstrSA)
|
||||
role, err2 := getObject(dstrRole)
|
||||
rb, err3 := getObject(dstrRB)
|
||||
|
||||
if err1 == nil && err2 == nil && err3 == nil {
|
||||
deleteAuthz(applier, rb)
|
||||
deleteAuthz(applier, role)
|
||||
deleteAuthz(applier, sa)
|
||||
if delCache {
|
||||
//delete from service cache
|
||||
utils.DeleteCache(utils.ServiceAccountCache, key)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
svclogger.Error(
|
||||
nil,
|
||||
"failed to cleanup service account",
|
||||
"serviceaccount", string(dstrSA),
|
||||
"role", string(dstrRole),
|
||||
"rolebinding", string(dstrRB),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func getObject(yamlData []byte) (k8sclient.Object, error) {
|
||||
jb, err := yaml.YAMLToJSON(yamlData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var so clusterv2.StepObject
|
||||
err = json.Unmarshal(jb, &so)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
o, _, err := cruntime.ToUnstructuredObject(&so)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func deleteAuthz(applier apply.Applier, obj k8sclient.Object) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
err := applier.Delete(ctx, obj)
|
||||
if err != nil {
|
||||
svclogger.Error(
|
||||
err,
|
||||
"failed to delete sa/role/rolebinding",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
k8proxy "k8s.io/apimachinery/pkg/util/proxy"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
)
|
||||
|
||||
// TCPProxy forwards TCP streams.
|
||||
type TCPProxy struct {
|
||||
// logger is the proxy logger.
|
||||
logger *relaylogger.RelayLog
|
||||
config *utils.ProxyConfig
|
||||
handler *k8proxy.UpgradeAwareHandler
|
||||
//kube-apiserver address
|
||||
apiHost string
|
||||
}
|
||||
|
||||
func (tp *TCPProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
u, err := url.Parse(tp.apiHost)
|
||||
if err == nil {
|
||||
r.URL.Host = u.Host
|
||||
r.URL.Scheme = u.Scheme
|
||||
r.Host = u.Host
|
||||
}
|
||||
r.Header.Set("Host", tp.apiHost)
|
||||
utils.UnSetXForwardedRafay(r.Header)
|
||||
tp.handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (tp *TCPProxy) backendProxy() error {
|
||||
socketPath := utils.UNIXAGENTSOCKET + tp.config.ServiceSNI
|
||||
syscall.Unlink(socketPath)
|
||||
|
||||
l, err := net.Listen("unix", socketPath)
|
||||
if err != nil {
|
||||
tp.logger.Error(
|
||||
err,
|
||||
"failed to listen on unix",
|
||||
"socketPath", socketPath,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
tp.logger.Info(
|
||||
"started listening on unix",
|
||||
"socketPath", socketPath,
|
||||
)
|
||||
|
||||
cfg, err := config.GetConfig()
|
||||
if err != nil {
|
||||
tp.logger.Error(
|
||||
err,
|
||||
"failed in NewKubeHandler",
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
hndlr, err := NewCachedKubeHandler(cfg, utils.DefaultKeepAliveInterval)
|
||||
if err != nil {
|
||||
tp.logger.Error(
|
||||
err,
|
||||
"unable to create kube handler for config",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
tp.handler = hndlr
|
||||
|
||||
go func() {
|
||||
|
||||
s := &http.Server{
|
||||
Handler: http.Handler(tp),
|
||||
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
|
||||
}
|
||||
|
||||
if err := s.Serve(l); err != nil {
|
||||
tp.logger.Error(
|
||||
err,
|
||||
"unable to start backend server",
|
||||
)
|
||||
}
|
||||
}()
|
||||
|
||||
tp.handler = hndlr
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewKubeCtlTCPProxy creates new direct TCPProxy, everything will be proxied to
|
||||
// unix socket.
|
||||
func NewKubeCtlTCPProxy(lg *relaylogger.RelayLog, cfg *utils.ProxyConfig) *TCPProxy {
|
||||
tp := &TCPProxy{
|
||||
logger: lg,
|
||||
config: cfg,
|
||||
}
|
||||
|
||||
err := tp.backendProxy()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
|
||||
if len(host) == 0 || len(port) == 0 {
|
||||
ec, err := config.GetConfig()
|
||||
if err != nil {
|
||||
tp.logger.Error(
|
||||
err,
|
||||
"failed to get kubeapi host:port",
|
||||
)
|
||||
return nil
|
||||
}
|
||||
tp.apiHost = ec.Host
|
||||
} else {
|
||||
tp.apiHost = "https://" + net.JoinHostPort(host, port)
|
||||
}
|
||||
|
||||
return tp
|
||||
}
|
||||
|
||||
// NewTCPProxy creates new direct TCPProxy, everything will be proxied to
|
||||
// unix socket.
|
||||
func NewTCPProxy(lg *relaylogger.RelayLog, cfg *utils.ProxyConfig) *TCPProxy {
|
||||
tp := &TCPProxy{
|
||||
logger: lg,
|
||||
config: cfg,
|
||||
}
|
||||
|
||||
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
|
||||
if len(host) == 0 || len(port) == 0 {
|
||||
ec, err := config.GetConfig()
|
||||
if err != nil {
|
||||
tp.logger.Error(
|
||||
err,
|
||||
"failed to get kubeapi host:port",
|
||||
)
|
||||
return nil
|
||||
}
|
||||
tp.apiHost = ec.Host
|
||||
} else {
|
||||
tp.apiHost = "https://" + net.JoinHostPort(host, port)
|
||||
}
|
||||
|
||||
return tp
|
||||
}
|
||||
|
||||
// Proxy is a ProxyFunc.
|
||||
func (tp *TCPProxy) Proxy(w io.Writer, r io.ReadCloser, msg *utils.ControlMessage, req *http.Request) {
|
||||
var target string
|
||||
var network string
|
||||
var directionTO, directionFrom string
|
||||
|
||||
switch tp.config.Protocol {
|
||||
case utils.CDAGENTCORE:
|
||||
if tp.config.Upstream != "" {
|
||||
target = tp.config.Upstream
|
||||
} else {
|
||||
target = utils.DefaultTCPUpstream
|
||||
}
|
||||
network = "tcp"
|
||||
directionTO = "tunnel to TCP"
|
||||
directionFrom = "TCP to tunnel"
|
||||
default:
|
||||
target = utils.UNIXAGENTSOCKET + tp.config.ServiceSNI
|
||||
network = "unix"
|
||||
directionTO = "tunnel to unix"
|
||||
directionFrom = "unix to tunnel"
|
||||
}
|
||||
|
||||
if target == "" {
|
||||
tp.logger.Info(
|
||||
"no unix target",
|
||||
"ctrlMsg", msg,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
local, err := net.DialTimeout(network, target, utils.DefaultMuxTimeout)
|
||||
if err != nil {
|
||||
tp.logger.Error(
|
||||
err,
|
||||
"msg dial failed",
|
||||
"target", target,
|
||||
"ctrlMsg", msg,
|
||||
"err", err,
|
||||
)
|
||||
return
|
||||
}
|
||||
defer local.Close()
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
utils.Transfer(flushWriter{w, tp.logger, local}, local, tp.logger, directionFrom)
|
||||
close(done)
|
||||
}()
|
||||
|
||||
utils.Transfer(local, r, tp.logger, directionTO)
|
||||
|
||||
proxyDone:
|
||||
for {
|
||||
select {
|
||||
case <-req.Context().Done():
|
||||
break proxyDone
|
||||
case <-done:
|
||||
break proxyDone
|
||||
}
|
||||
}
|
||||
// wait fr 2 sec before closing
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
type flushWriter struct {
|
||||
w io.Writer
|
||||
lg *relaylogger.RelayLog
|
||||
c net.Conn
|
||||
}
|
||||
|
||||
func (fw flushWriter) Write(p []byte) (n int, err error) {
|
||||
n, err = fw.w.Write(p)
|
||||
fw.lg.Debug(
|
||||
"data wrote",
|
||||
"data", string(p),
|
||||
)
|
||||
if f, ok := fw.w.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
} else {
|
||||
fw.lg.Info(
|
||||
"flushWriter http.Flusher not ok",
|
||||
)
|
||||
}
|
||||
// tolerate up to utils.IdleTimeout idletime
|
||||
fw.c.SetDeadline(time.Now().Add(utils.IdleTimeout))
|
||||
return
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: rafay-core-debug
|
||||
namespace: default
|
||||
labels:
|
||||
creator: rafay-relay
|
||||
expire: "yes"
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: rafay-core-debug-role
|
||||
namespace: default
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- "*"
|
||||
verbs:
|
||||
- "*"
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: rafay-core-debug-binding
|
||||
namespace: default
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: rafay-core-debug-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: rafay-core-debug
|
||||
@@ -0,0 +1,888 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/sentry/cryptoutil"
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/sentry/register"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/tunnel"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
podNameEnv = "POD_NAME"
|
||||
podNamespaceEnv = "POD_NAMESPACE"
|
||||
peerServiceURIEnv = "RAFAY_RELAY_PEERSERVICE"
|
||||
relayListenIPEnv = "RELAY_LISTENIP"
|
||||
sentryAddrEnv = "SENTRY_ADDR" // used by relay running inside core
|
||||
auditPathEnv = "AUDIT_PATH"
|
||||
metricListenEnv = "METRIC_LISTEN"
|
||||
|
||||
// for relays running outside of core
|
||||
// supply bootstrapAddr and token as environment variables
|
||||
bootstrapAddrEnv = "BOOTSTRAP_ADDR"
|
||||
relayPeeringTokenEnv = "RELAY_PEERING_TOKEN"
|
||||
relayUserTokenEnv = "RELAY_USER_TOKEN"
|
||||
relayConnectorTokenEnv = "RELAY_CONNECTOR_TOKEN"
|
||||
relayUserHostPortEnv = "RELAY_USER_HOST_PORT"
|
||||
relayConnectorHostPortEnv = "RELAY_CONNECTOR_HOST_PORT"
|
||||
relayNetworkIDEnv = "RELAY_NETWORK_ID"
|
||||
|
||||
// cd relay
|
||||
cdRelayUserTokenEnv = "CD_RELAY_USER_TOKEN"
|
||||
cdRelayConnectorTokenEnv = "CD_RELAY_CONNECTOR_TOKEN"
|
||||
)
|
||||
|
||||
var (
|
||||
podName string
|
||||
podNamespace string
|
||||
relayPeeringURI string
|
||||
relayListenIP string
|
||||
log *relaylogger.RelayLog
|
||||
sentryAddr string // used by relay running inside core
|
||||
auditPath string
|
||||
metricListen string
|
||||
|
||||
// for relays running outside of core
|
||||
relayPeeringToken string
|
||||
relayConnectorToken string
|
||||
relayUserToken string
|
||||
bootstrapAddr string
|
||||
relayUserHostPort string
|
||||
relayConnectorHostPort string
|
||||
relayNetworkID string
|
||||
|
||||
// cd relay
|
||||
cdRelayConnectorToken string
|
||||
cdRelayUserToken string
|
||||
)
|
||||
|
||||
func setupserver(log *relaylogger.RelayLog) error {
|
||||
// Enable VIPER to read Environment Variables
|
||||
viper.AutomaticEnv()
|
||||
|
||||
viper.SetDefault(podNameEnv, "relay-pod")
|
||||
viper.SetDefault(podNamespace, "rafay-system")
|
||||
viper.SetDefault(peerServiceURIEnv, "https://peering.sentry.rafay.local:10001")
|
||||
viper.SetDefault(sentryAddrEnv, "localhost:10000")
|
||||
|
||||
// for relays running outside of core
|
||||
viper.SetDefault(bootstrapAddrEnv, "")
|
||||
viper.SetDefault(relayPeeringTokenEnv, "-")
|
||||
viper.SetDefault(relayUserToken, "-")
|
||||
viper.SetDefault(relayConnectorToken, "-")
|
||||
viper.SetDefault(relayUserHostPortEnv, "")
|
||||
viper.SetDefault(relayConnectorHostPortEnv, "")
|
||||
viper.SetDefault(auditPathEnv, "/tmp")
|
||||
viper.SetDefault(metricListenEnv, ":8003")
|
||||
viper.SetDefault(relayNetworkIDEnv, "rafay-core-64a66h0asw")
|
||||
|
||||
viper.BindEnv(podNameEnv)
|
||||
viper.BindEnv(podNamespaceEnv)
|
||||
viper.BindEnv(relayPeeringTokenEnv)
|
||||
viper.BindEnv(sentryAddrEnv)
|
||||
|
||||
// outside core configs
|
||||
viper.BindEnv(bootstrapAddrEnv)
|
||||
viper.BindEnv(relayUserHostPortEnv)
|
||||
viper.BindEnv(relayConnectorHostPortEnv)
|
||||
viper.BindEnv(relayUserTokenEnv)
|
||||
viper.BindEnv(relayConnectorTokenEnv)
|
||||
viper.BindEnv(relayNetworkIDEnv)
|
||||
|
||||
// for testing
|
||||
viper.BindEnv(relayListenIPEnv)
|
||||
|
||||
podName = viper.GetString(podNameEnv)
|
||||
podNamespace = viper.GetString(podNamespaceEnv)
|
||||
sentryAddr = viper.GetString(sentryAddrEnv)
|
||||
auditPath = viper.GetString(auditPathEnv)
|
||||
|
||||
utils.PODNAME = podName
|
||||
|
||||
relayPeeringURI = viper.GetString(peerServiceURIEnv)
|
||||
|
||||
// outside core relay configurations
|
||||
bootstrapAddr = viper.GetString(bootstrapAddrEnv)
|
||||
relayUserHostPort = viper.GetString(relayUserHostPortEnv)
|
||||
relayConnectorHostPort = viper.GetString(relayConnectorHostPortEnv)
|
||||
relayNetworkID = viper.GetString(relayNetworkIDEnv)
|
||||
|
||||
if sentryAddr == "" && bootstrapAddr == "" {
|
||||
log.Error(
|
||||
nil,
|
||||
"missing sentry & bootstrap uri, please set one of the environment variable RAFAY_SENTRY[relay deployed inside core] (or) BOOTSTRAP_ADDR[outside core]",
|
||||
)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
|
||||
if bootstrapAddr != "" {
|
||||
// outside config found, unset inside boostrap endpoint.
|
||||
// both cannot be set, only one mode is possible
|
||||
sentryAddr = ""
|
||||
}
|
||||
|
||||
if relayPeeringURI == "" {
|
||||
log.Error(
|
||||
nil,
|
||||
"missing relay peer service uri, please set RAFAY_RELAY_PEERSERVICE environment variable",
|
||||
)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
|
||||
relayPeeringToken = viper.GetString(relayPeeringTokenEnv)
|
||||
relayUserToken = viper.GetString(relayUserTokenEnv)
|
||||
relayConnectorToken = viper.GetString(relayConnectorTokenEnv)
|
||||
relayListenIP = viper.GetString(relayListenIPEnv) // used for running multiple relays in local test hosts
|
||||
metricListen = viper.GetString(metricListenEnv)
|
||||
|
||||
log.Info(
|
||||
"relay server setup values",
|
||||
"podName", podName,
|
||||
"podNamespace", podNamespace,
|
||||
"relayPeeringURI", relayPeeringURI,
|
||||
"relayListenIP", relayListenIP,
|
||||
)
|
||||
|
||||
if sentryAddr != "" {
|
||||
log.Info("relay inside core: sentryAddr", sentryAddr)
|
||||
} else {
|
||||
log.Info(
|
||||
"outside core relay: bootStrapURI", bootstrapAddr,
|
||||
"relayPeeringToken", relayPeeringToken,
|
||||
"relayUserToken", relayUserToken,
|
||||
"relayConnectorToken", relayConnectorToken,
|
||||
)
|
||||
if relayPeeringToken == "-" || relayUserToken == "-" || relayConnectorToken == "-" || relayUserHostPort == "" || relayConnectorHostPort == "" {
|
||||
log.Error(
|
||||
fmt.Errorf("missing env variable"),
|
||||
"outside core relay: one of the required token is missing, please set missing environment variables",
|
||||
"RELAY_PEERING_TOKEN", relayPeeringToken,
|
||||
"RELAY_USER_TOKEN", relayUserToken,
|
||||
"RELAY_CONNECTOR_TOKEN", relayConnectorToken,
|
||||
"RELAY_USER_HOST_PORT", relayUserHostPort,
|
||||
"RELAY_CONNECTOR_HOST_PORT", relayConnectorHostPort,
|
||||
)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
|
||||
// process the user facing host:port
|
||||
host, port, err := net.SplitHostPort(relayUserHostPort)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to process RELAY_USER_HOST_PORT env variable", relayUserHostPort,
|
||||
)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
utils.RelayUserPort, err = strconv.Atoi(port)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"invalid port in RELAY_USER_HOST_PORT env variable", relayUserHostPort,
|
||||
)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
utils.RelayUserHost = host
|
||||
|
||||
// process the connector facing host:port
|
||||
host, port, err = net.SplitHostPort(relayConnectorHostPort)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to process RELAY_CONNECTOR_HOST_PORT env variable", relayConnectorHostPort,
|
||||
)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
utils.RelayConnectorPort, err = strconv.Atoi(port)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"invalid port in RELAY_CONNECTOR_HOST_PORT env variable", relayConnectorHostPort,
|
||||
)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
utils.RelayConnectorHost = host
|
||||
}
|
||||
|
||||
utils.RelayIPFromConfig = relayListenIP
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupCDServer(log *relaylogger.RelayLog) error {
|
||||
// Enable VIPER to read Environment Variables
|
||||
viper.AutomaticEnv()
|
||||
|
||||
viper.SetDefault(podNameEnv, "cdrelay-pod")
|
||||
viper.SetDefault(podNamespace, "rafay-system")
|
||||
viper.SetDefault(peerServiceURIEnv, "https://peering.sentry.rafay.local:10001")
|
||||
viper.SetDefault(sentryAddrEnv, "localhost:10000")
|
||||
|
||||
// for relays running outside of core
|
||||
viper.SetDefault(bootstrapAddrEnv, "")
|
||||
viper.SetDefault(relayPeeringTokenEnv, "-")
|
||||
viper.SetDefault(cdRelayUserTokenEnv, "-")
|
||||
viper.SetDefault(cdRelayConnectorTokenEnv, "-")
|
||||
viper.SetDefault(auditPathEnv, "/tmp")
|
||||
viper.SetDefault(metricListenEnv, ":8003")
|
||||
|
||||
viper.BindEnv(podNameEnv)
|
||||
viper.BindEnv(podNamespaceEnv)
|
||||
viper.BindEnv(relayPeeringTokenEnv)
|
||||
viper.BindEnv(sentryAddrEnv)
|
||||
|
||||
// outside core configs
|
||||
viper.BindEnv(bootstrapAddrEnv)
|
||||
viper.BindEnv(cdRelayUserTokenEnv)
|
||||
viper.BindEnv(cdRelayConnectorTokenEnv)
|
||||
|
||||
// for testing
|
||||
viper.BindEnv(relayListenIPEnv)
|
||||
|
||||
podName = viper.GetString(podNameEnv)
|
||||
podNamespace = viper.GetString(podNamespaceEnv)
|
||||
sentryAddr = viper.GetString(sentryAddrEnv)
|
||||
auditPath = viper.GetString(auditPathEnv)
|
||||
|
||||
utils.PODNAME = podName
|
||||
|
||||
relayPeeringURI = viper.GetString(peerServiceURIEnv)
|
||||
|
||||
if sentryAddr == "" {
|
||||
log.Error(
|
||||
nil,
|
||||
"missing sentry uri, please set one of the environment variable RAFAY_SENTRY[relay deployed inside core] (or) BOOTSTRAP_ADDR[outside core]",
|
||||
)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
|
||||
if relayPeeringURI == "" {
|
||||
log.Error(
|
||||
nil,
|
||||
"missing relay peer service uri, please set RAFAY_RELAY_PEERSERVICE environment variable",
|
||||
)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
|
||||
relayPeeringToken = viper.GetString(relayPeeringTokenEnv)
|
||||
cdRelayUserToken = viper.GetString(cdRelayUserTokenEnv)
|
||||
cdRelayConnectorToken = viper.GetString(cdRelayConnectorTokenEnv)
|
||||
relayListenIP = viper.GetString(relayListenIPEnv) // used for running multiple relays in local test hosts
|
||||
metricListen = viper.GetString(metricListenEnv)
|
||||
|
||||
log.Debug(
|
||||
"relay server setup values",
|
||||
"podName", podName,
|
||||
"podNamespace", podNamespace,
|
||||
"relayPeeringURI", relayPeeringURI,
|
||||
"relayListenIP", relayListenIP,
|
||||
)
|
||||
|
||||
utils.RelayIPFromConfig = relayListenIP
|
||||
return nil
|
||||
}
|
||||
|
||||
// prepare config for outside relay boot strapping
|
||||
func prepareConfigCSRForBootStrapOutSideCore(config *register.Config, CN string, log *relaylogger.RelayLog) error {
|
||||
privKey, err := cryptoutil.GenerateECDSAPrivateKey()
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed generate ecd private key with CN", CN,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
key, err := cryptoutil.EncodePrivateKey(privKey, cryptoutil.NoPassword)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed encode ecd private key with CN", CN,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
config.PrivateKey = key
|
||||
|
||||
csr, err := cryptoutil.CreateCSR(pkix.Name{
|
||||
CommonName: CN,
|
||||
Country: []string{"USA"},
|
||||
Organization: []string{"Rafay Systems Inc"},
|
||||
Province: []string{"California"},
|
||||
Locality: []string{"Sunnyvale"},
|
||||
OrganizationalUnit: []string{relayNetworkID},
|
||||
}, privKey)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed create CSR with CN", CN,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
config.CSR = csr
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerRelayPeerService will register with rafay-sentry-peering-client template token
|
||||
// registration fetches client-certificate/root-ca to connect to sentry peer service
|
||||
func registerRelayPeerService(ctx context.Context, log *relaylogger.RelayLog) error {
|
||||
cfg := ®ister.Config{
|
||||
ClientID: "peering-" + podName,
|
||||
ClientIP: utils.GetRelayIP(),
|
||||
Name: "peering-" + podName,
|
||||
Mode: "client",
|
||||
}
|
||||
|
||||
if bootstrapAddr != "" {
|
||||
// outside core bootstrap
|
||||
cfg.Addr = bootstrapAddr
|
||||
if relayPeeringToken == "" {
|
||||
return fmt.Errorf("empty peering token for bootstrap")
|
||||
}
|
||||
cfg.TemplateToken = relayPeeringToken
|
||||
cfg.Scheme = "http"
|
||||
// check port is 443 then set scheme as https
|
||||
if utils.IsHTTPS(bootstrapAddr) {
|
||||
cfg.Scheme = "https"
|
||||
}
|
||||
// this is a client certificate CN is same as ClientID
|
||||
err := prepareConfigCSRForBootStrapOutSideCore(cfg, cfg.ClientID, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed in config csr for relay peering bootstrap")
|
||||
}
|
||||
} else {
|
||||
cfg.TemplateToken = "template/-"
|
||||
cfg.Addr = sentryAddr
|
||||
cfg.Scheme = "grpc"
|
||||
cfg.TemplateName = "rafay-sentry-peering-client"
|
||||
}
|
||||
|
||||
if err := register.Register(ctx, cfg); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register peering relay",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"peer certificate:",
|
||||
string(cfg.Certificate),
|
||||
)
|
||||
|
||||
utils.PeerCertificate = cfg.Certificate
|
||||
utils.PeerPrivateKey = cfg.PrivateKey
|
||||
utils.PeerCACertificate = cfg.CACertificate
|
||||
utils.PeerServiceURI = relayPeeringURI
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerCDRelayPeerService will register with rafay-sentry-cd-peering-client template token
|
||||
// registration fetches client-certificate/root-ca to connect to sentry peer service
|
||||
func registerCDRelayPeerService(ctx context.Context, log *relaylogger.RelayLog) error {
|
||||
cfg := ®ister.Config{
|
||||
ClientID: "peering-" + podName,
|
||||
ClientIP: utils.GetRelayIP(),
|
||||
Name: "peering-" + podName,
|
||||
Mode: "client",
|
||||
}
|
||||
|
||||
if bootstrapAddr != "" {
|
||||
// outside core bootstrap
|
||||
cfg.Addr = bootstrapAddr
|
||||
if relayPeeringToken == "" {
|
||||
return fmt.Errorf("empty peering token for bootstrap")
|
||||
}
|
||||
cfg.TemplateToken = relayPeeringToken
|
||||
cfg.Scheme = "http"
|
||||
// check port is 443 then set scheme as https
|
||||
if utils.IsHTTPS(bootstrapAddr) {
|
||||
cfg.Scheme = "https"
|
||||
}
|
||||
// this is a client certificate CN is same as ClientID
|
||||
err := prepareConfigCSRForBootStrapOutSideCore(cfg, cfg.ClientID, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed in config csr for relay peering bootstrap")
|
||||
}
|
||||
} else {
|
||||
cfg.TemplateToken = "template/cd-relay"
|
||||
cfg.Addr = sentryAddr
|
||||
cfg.Scheme = "grpc"
|
||||
cfg.TemplateName = "rafay-sentry-cd-peering-client"
|
||||
}
|
||||
|
||||
if err := register.Register(ctx, cfg); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register cd peering relay",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"peer certificate:",
|
||||
string(cfg.Certificate),
|
||||
)
|
||||
|
||||
utils.PeerCertificate = cfg.Certificate
|
||||
utils.PeerPrivateKey = cfg.PrivateKey
|
||||
utils.PeerCACertificate = cfg.CACertificate
|
||||
utils.PeerServiceURI = relayPeeringURI
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerRelayUserServer will register with rafay-core-relay-user template token
|
||||
// registration fetches client-certificate/root-ca to terminate user connections
|
||||
// the same certificate will be used as the client cert for peer-upstreams
|
||||
func registerRelayUserServer(ctx context.Context, log *relaylogger.RelayLog) error {
|
||||
cfg := ®ister.Config{
|
||||
ClientID: "user-" + podName,
|
||||
ClientIP: utils.GetRelayIP(),
|
||||
Name: "user-" + podName,
|
||||
Mode: "server",
|
||||
}
|
||||
|
||||
if bootstrapAddr != "" {
|
||||
// outside core bootstrap
|
||||
cfg.Addr = bootstrapAddr
|
||||
if relayUserToken == "" {
|
||||
return fmt.Errorf("empty user token for bootstrap")
|
||||
}
|
||||
cfg.TemplateToken = relayUserToken
|
||||
cfg.Scheme = "http"
|
||||
// check port is 443 then set scheme as https
|
||||
if utils.IsHTTPS(bootstrapAddr) {
|
||||
cfg.Scheme = "https"
|
||||
}
|
||||
// this is a server certificate CN is same as ServerHost
|
||||
cfg.ServerHost = utils.RelayUserHost
|
||||
cfg.ServerPort = utils.RelayUserPort
|
||||
err := prepareConfigCSRForBootStrapOutSideCore(cfg, cfg.ServerHost, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed in config csr for relay user server bootstrap")
|
||||
}
|
||||
} else {
|
||||
cfg.Addr = sentryAddr
|
||||
cfg.Scheme = "grpc"
|
||||
cfg.TemplateName = "rafay-core-relay-user"
|
||||
}
|
||||
|
||||
if err := register.Register(ctx, cfg); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register user relay",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"user certificate:",
|
||||
string(cfg.Certificate),
|
||||
)
|
||||
|
||||
utils.RelayUserCert = cfg.Certificate
|
||||
utils.RelayUserKey = cfg.PrivateKey
|
||||
utils.RelayUserCACert = cfg.CACertificate
|
||||
utils.RelayUserPort = cfg.ServerPort
|
||||
utils.RelayUserHost = cfg.ServerHost
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerCDRelayUserServer will register with rafay-core-cd-relay-user template token
|
||||
// registration fetches client-certificate/root-ca to terminate user connections
|
||||
// the same certificate will be used as the client cert for peer-upstreams
|
||||
func registerCDRelayUserServer(ctx context.Context, log *relaylogger.RelayLog) error {
|
||||
cfg := ®ister.Config{
|
||||
ClientID: "cd-user-" + podName,
|
||||
ClientIP: utils.GetRelayIP(),
|
||||
Name: "cd-user-" + podName,
|
||||
Mode: "server",
|
||||
}
|
||||
|
||||
//inside core bootstrap
|
||||
cfg.Addr = sentryAddr
|
||||
cfg.Scheme = "grpc"
|
||||
cfg.TemplateName = "rafay-core-cd-relay-user"
|
||||
|
||||
if err := register.Register(ctx, cfg); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register user cd relay",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"user certificate:",
|
||||
string(cfg.Certificate),
|
||||
)
|
||||
|
||||
utils.CDRelayUserCert = cfg.Certificate
|
||||
utils.CDRelayUserKey = cfg.PrivateKey
|
||||
utils.CDRelayUserCACert = cfg.CACertificate
|
||||
utils.CDRelayUserPort = cfg.ServerPort
|
||||
utils.CDRelayUserHost = cfg.ServerHost
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerRelayConnectorServer will register with rafay-core-relay-connector template token
|
||||
// registration fetches client-certificate/root-ca to terminate connector connections
|
||||
// the same certificate will be used as the client cert for peer-upstreams
|
||||
func registerRelayConnectorServer(ctx context.Context, log *relaylogger.RelayLog) error {
|
||||
cfg := ®ister.Config{
|
||||
ClientID: "relay-server-" + podName,
|
||||
ClientIP: utils.GetRelayIP(),
|
||||
Name: "relay-server-" + podName,
|
||||
Mode: "server",
|
||||
}
|
||||
|
||||
if bootstrapAddr != "" {
|
||||
// outside core bootstrap
|
||||
cfg.Addr = bootstrapAddr
|
||||
if relayConnectorToken == "" {
|
||||
return fmt.Errorf("empty user token for bootstrap")
|
||||
}
|
||||
cfg.TemplateToken = relayConnectorToken
|
||||
cfg.Scheme = "http"
|
||||
// check port is 443 then set scheme as https
|
||||
if utils.IsHTTPS(bootstrapAddr) {
|
||||
cfg.Scheme = "https"
|
||||
}
|
||||
// this is a server certificate CN is same as ServerHost
|
||||
cfg.ServerHost = utils.RelayConnectorHost
|
||||
cfg.ServerPort = utils.RelayConnectorPort
|
||||
err := prepareConfigCSRForBootStrapOutSideCore(cfg, cfg.ServerHost, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed in config csr for relay connector server bootstrap")
|
||||
}
|
||||
} else {
|
||||
//inside core bootstrap
|
||||
cfg.Addr = sentryAddr
|
||||
cfg.Scheme = "grpc"
|
||||
cfg.TemplateName = "rafay-core-relay-server"
|
||||
}
|
||||
|
||||
if err := register.Register(ctx, cfg); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register connector relay",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"connector certificate:",
|
||||
string(cfg.Certificate),
|
||||
)
|
||||
|
||||
utils.RelayConnectorCert = cfg.Certificate
|
||||
utils.RelayConnectorKey = cfg.PrivateKey
|
||||
utils.RelayConnectorCACert = cfg.CACertificate
|
||||
utils.RelayConnectorHost = cfg.ServerHost
|
||||
utils.RelayConnectorPort = cfg.ServerPort
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerCDRelayConnectorServer will register with rafay-core-cd-relay-connector template token
|
||||
// registration fetches client-certificate/root-ca to terminate connector connections
|
||||
// the same certificate will be used as the client cert for peer-upstreams
|
||||
func registerCDRelayConnectorServer(ctx context.Context, log *relaylogger.RelayLog) error {
|
||||
cfg := ®ister.Config{
|
||||
ClientID: "cd-relay-server-" + podName,
|
||||
ClientIP: utils.GetRelayIP(),
|
||||
Name: "cd-relay-server-" + podName,
|
||||
Mode: "server",
|
||||
}
|
||||
|
||||
//inside core bootstrap
|
||||
cfg.Addr = sentryAddr
|
||||
cfg.Scheme = "grpc"
|
||||
cfg.TemplateName = "rafay-core-cd-relay-server"
|
||||
|
||||
if err := register.Register(ctx, cfg); err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register connector cd relay",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info(
|
||||
"connector certificate:",
|
||||
string(cfg.Certificate),
|
||||
)
|
||||
|
||||
utils.CDRelayConnectorCert = cfg.Certificate
|
||||
utils.CDRelayConnectorKey = cfg.PrivateKey
|
||||
utils.CDRelayConnectorCACert = cfg.CACertificate
|
||||
utils.CDRelayConnectorHost = cfg.ServerHost
|
||||
utils.CDRelayConnectorPort = cfg.ServerPort
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func relayServerBootStrap(ctx context.Context, log *relaylogger.RelayLog) {
|
||||
//peer service bootstrap
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
for {
|
||||
err := registerRelayPeerService(ctx, log)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register relay with peer-service-bootstrap service, will retry",
|
||||
)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
continue
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
ticker.Stop()
|
||||
|
||||
ticker = time.NewTicker(5 * time.Second)
|
||||
// relay user server bootstrap
|
||||
for {
|
||||
err := registerRelayUserServer(ctx, log)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register relay with relay-user-bootstrap service, will retry",
|
||||
)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
continue
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
ticker.Stop()
|
||||
|
||||
ticker = time.NewTicker(5 * time.Second)
|
||||
// relay connector server bootstrap
|
||||
for {
|
||||
err := registerRelayConnectorServer(ctx, log)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register relay with relay-connector-bootstrap service, will retry",
|
||||
)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
continue
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
ticker.Stop()
|
||||
}
|
||||
|
||||
func cdRelayServerBootStrap(ctx context.Context, log *relaylogger.RelayLog) {
|
||||
//peer service bootstrap
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
for {
|
||||
err := registerCDRelayPeerService(ctx, log)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register cd relay with peer-service-bootstrap service, will retry",
|
||||
)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
continue
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
ticker.Stop()
|
||||
|
||||
ticker = time.NewTicker(5 * time.Second)
|
||||
// relay user server bootstrap
|
||||
for {
|
||||
err := registerCDRelayUserServer(ctx, log)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register relay with cd-relay-user-bootstrap service, will retry",
|
||||
)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
continue
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
ticker.Stop()
|
||||
|
||||
ticker = time.NewTicker(5 * time.Second)
|
||||
// relay connector server bootstrap
|
||||
for {
|
||||
err := registerCDRelayConnectorServer(ctx, log)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
err,
|
||||
"failed to register relay with cd-relay-connector-bootstrap service, will retry",
|
||||
)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
continue
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
ticker.Stop()
|
||||
}
|
||||
|
||||
//RunRelayServer entry to the relay server
|
||||
func RunRelayServer(ctx context.Context, logLvl int) {
|
||||
rctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
log = relaylogger.NewLogger(logLvl).WithName("Relay Server")
|
||||
|
||||
if err := setupserver(log); err != nil {
|
||||
//config is not available
|
||||
log.Error(
|
||||
err,
|
||||
"relay server exiting",
|
||||
)
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
restartServer:
|
||||
relayServerBootStrap(rctx, log)
|
||||
go tunnel.StartServer(rctx, log, fmt.Sprintf("%s/%s", auditPath, podName), utils.ExitChan)
|
||||
go runMetricServer(rctx, log)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-utils.ExitChan:
|
||||
log.Info(
|
||||
"Relay server stopped, restart in 2 secs",
|
||||
)
|
||||
time.Sleep(2 * time.Second)
|
||||
goto restartServer
|
||||
case <-ctx.Done():
|
||||
log.Info(
|
||||
"Relay server exiting",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//RunCDRelayServer entry to the relay server
|
||||
func RunCDRelayServer(ctx context.Context, logLvl int) {
|
||||
rctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
log = relaylogger.NewLogger(logLvl).WithName("Relay Server")
|
||||
|
||||
if err := setupCDServer(log); err != nil {
|
||||
//config is not available
|
||||
log.Error(
|
||||
err,
|
||||
"relay server exiting",
|
||||
)
|
||||
utils.ExitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
restartServer:
|
||||
cdRelayServerBootStrap(rctx, log)
|
||||
go tunnel.StartCDServer(rctx, log, fmt.Sprintf("%s/%s", auditPath, podName), utils.ExitChan)
|
||||
go runMetricServer(rctx, log)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-utils.ExitChan:
|
||||
log.Info(
|
||||
"Relay server stopped, restart in 2 secs",
|
||||
)
|
||||
time.Sleep(2 * time.Second)
|
||||
goto restartServer
|
||||
case <-ctx.Done():
|
||||
log.Info(
|
||||
"Relay server exiting",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runMetricServer(ctx context.Context, log *relaylogger.RelayLog) {
|
||||
|
||||
m := http.NewServeMux()
|
||||
s := http.Server{Addr: metricListen, Handler: m}
|
||||
m.HandleFunc("/dialins", dialinMetrics)
|
||||
m.HandleFunc("/loglevel", setLoglevel)
|
||||
m.HandleFunc("/health", healthCheck)
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
s.Shutdown(context.Background())
|
||||
}()
|
||||
log.Info("Start Relay Metric Server at", metricListen)
|
||||
err := s.ListenAndServe()
|
||||
log.Info("Stopping Relay Metric Server at", metricListen, err)
|
||||
}
|
||||
|
||||
func dialinMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
tunnel.DialinMetric(w)
|
||||
}
|
||||
|
||||
func setLoglevel(w http.ResponseWriter, r *http.Request) {
|
||||
keys, ok := r.URL.Query()["level"]
|
||||
if !ok || len(keys[0]) < 1 {
|
||||
fmt.Fprintf(w, "missing level query string")
|
||||
return
|
||||
}
|
||||
|
||||
level := keys[0]
|
||||
lvl, err := strconv.Atoi(level)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "invalid level query string")
|
||||
return
|
||||
}
|
||||
|
||||
relaylogger.SetRunTimeLogLevel(lvl)
|
||||
|
||||
fmt.Fprintf(w, "Success: set loglevel to "+level)
|
||||
}
|
||||
|
||||
func healthCheck(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "up and feels good")
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package relaylogger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
logtmp = log.GetLogger()
|
||||
plain = logtmp.SugaredLogger.Desugar().WithOptions(zap.AddCallerSkip(2))
|
||||
rlog = plain.Sugar()
|
||||
runLevel = 0
|
||||
)
|
||||
|
||||
// RelayLog is a sample logr.Logger that logs to stderr.
|
||||
// It's terribly inefficient, and is *only* a basic example.
|
||||
type RelayLog struct {
|
||||
level int
|
||||
name string
|
||||
keyValues map[string]interface{}
|
||||
}
|
||||
|
||||
func (l *RelayLog) relaylog(level int, msg string, kvs ...interface{}) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
if level > runLevel {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(&buf, "%s::%s ", l.name, msg)
|
||||
for k, v := range l.keyValues {
|
||||
fmt.Fprintf(&buf, "%s: %+v ", k, v)
|
||||
}
|
||||
|
||||
if len(kvs)%2 == 0 {
|
||||
for i := 0; i < len(kvs); i += 2 {
|
||||
fmt.Fprintf(&buf, "%s: %+v ", kvs[i], kvs[i+1])
|
||||
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(kvs); i++ {
|
||||
fmt.Fprintf(&buf, "%+v ", kvs[i])
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(&buf, "\n")
|
||||
switch level {
|
||||
case 0:
|
||||
rlog.Panicw(buf.String())
|
||||
case 1:
|
||||
rlog.Errorw(buf.String())
|
||||
case 2:
|
||||
rlog.Warnw(buf.String())
|
||||
case 3:
|
||||
rlog.Infow(buf.String())
|
||||
case 4:
|
||||
rlog.Debugw(buf.String())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Enabled log enabled
|
||||
func (_ *RelayLog) Enabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
//Critical log critical
|
||||
func (l *RelayLog) Critical(msg string, kvs ...interface{}) {
|
||||
l.relaylog(0, msg, kvs...)
|
||||
}
|
||||
|
||||
//Error log error level
|
||||
func (l *RelayLog) Error(err error, msg string, kvs ...interface{}) {
|
||||
kvs = append(kvs, "error", err)
|
||||
l.relaylog(1, msg, kvs...)
|
||||
}
|
||||
|
||||
//Warn log warning level
|
||||
func (l *RelayLog) Warn(msg string, kvs ...interface{}) {
|
||||
l.relaylog(2, msg, kvs...)
|
||||
}
|
||||
|
||||
//Info log info level
|
||||
func (l *RelayLog) Info(msg string, kvs ...interface{}) {
|
||||
l.relaylog(3, msg, kvs...)
|
||||
}
|
||||
|
||||
//Debug log debug level
|
||||
func (l *RelayLog) Debug(msg string, kvs ...interface{}) {
|
||||
l.relaylog(4, msg, kvs...)
|
||||
}
|
||||
|
||||
//V ..
|
||||
func (l *RelayLog) V(_ int) *RelayLog {
|
||||
return l
|
||||
}
|
||||
|
||||
//WithName set log name
|
||||
func (l *RelayLog) WithName(name string) *RelayLog {
|
||||
var objName string
|
||||
if l.name == "" {
|
||||
objName = name
|
||||
} else {
|
||||
objName = l.name + "." + name
|
||||
}
|
||||
|
||||
return &RelayLog{
|
||||
level: l.level,
|
||||
name: objName,
|
||||
keyValues: l.keyValues,
|
||||
}
|
||||
}
|
||||
|
||||
//WithValues log key values
|
||||
func (l *RelayLog) WithValues(kvs ...interface{}) *RelayLog {
|
||||
newMap := make(map[string]interface{}, len(l.keyValues)+len(kvs)/2)
|
||||
for k, v := range l.keyValues {
|
||||
newMap[k] = v
|
||||
}
|
||||
for i := 0; i < len(kvs); i += 2 {
|
||||
newMap[kvs[i].(string)] = kvs[i+1]
|
||||
}
|
||||
return &RelayLog{
|
||||
level: l.level,
|
||||
name: l.name,
|
||||
keyValues: newMap,
|
||||
}
|
||||
}
|
||||
|
||||
//NewLogger create new logger
|
||||
func NewLogger(level int) *RelayLog {
|
||||
if runLevel < level {
|
||||
runLevel = level
|
||||
}
|
||||
return &RelayLog{level: level}
|
||||
}
|
||||
|
||||
//SetRunTimeLogLevel set a run time log level
|
||||
func SetRunTimeLogLevel(level int) {
|
||||
fmt.Println("log level changed from ", runLevel, " to ", level)
|
||||
runLevel = level
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package sessions
|
||||
|
||||
import (
|
||||
"hash"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/twmb/murmur3"
|
||||
)
|
||||
|
||||
//UserSession session cache
|
||||
type UserSession struct {
|
||||
// Type of the server. Relay means user-facing
|
||||
// Dialin means cluster-facing
|
||||
Type string
|
||||
|
||||
// ServerName of the server which accepted the connection
|
||||
ServerName string
|
||||
|
||||
// CertSNI derived from client certificate
|
||||
CertSNI string
|
||||
|
||||
// server block of this connection
|
||||
//server *Server
|
||||
|
||||
// DialinCachedKey already stiched to a dialin
|
||||
DialinCachedKey string
|
||||
|
||||
// ErrorFlag indicate the session got 401/502
|
||||
ErrorFlag bool
|
||||
|
||||
// UserName used in login
|
||||
UserName string
|
||||
|
||||
// RoleName Role
|
||||
RoleName string
|
||||
|
||||
// IsReadrole read/write
|
||||
IsReadrole bool
|
||||
|
||||
// IsReadrole OrgAdmin
|
||||
IsOrgAdmin bool
|
||||
|
||||
// EnforceOrgAdminOnlySecret access
|
||||
EnforceOrgAdminOnlySecret bool
|
||||
}
|
||||
|
||||
var (
|
||||
// userSessions cache
|
||||
userSessions *ristretto.Cache
|
||||
|
||||
// for URL matching
|
||||
roleCheck *httprouter.Router
|
||||
|
||||
// for URL matching
|
||||
roleCheckSecret *httprouter.Router
|
||||
|
||||
_hashPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
// The Pool's New function should generally only return pointer
|
||||
// types, since a pointer can be put into the return interface
|
||||
// value without an allocation:
|
||||
return murmur3.New64()
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
var _dummyHandler = func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {}
|
||||
|
||||
//InitUserSessionCache init user cache
|
||||
func InitUserSessionCache() error {
|
||||
var err error
|
||||
userSessions, err = ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1e4, // Num keys to track frequency of (10k).
|
||||
MaxCost: 1 << 25, // Maximum cost of cache (32MB).
|
||||
BufferItems: 64, // Number of keys per Get buffer.
|
||||
})
|
||||
|
||||
roleCheck = httprouter.New()
|
||||
roleCheck.Handle("POST", "/api/:version/namespaces/:namespace/pods/:pod/exec", _dummyHandler)
|
||||
roleCheck.Handle("POST", "/api/:version/namespaces/:namespace/secrets", _dummyHandler)
|
||||
roleCheck.Handle("GET", "/api/:version/namespaces/:namespace/secrets", _dummyHandler)
|
||||
roleCheck.Handle("GET", "/api/:version/secrets", _dummyHandler)
|
||||
|
||||
roleCheckSecret = httprouter.New()
|
||||
roleCheckSecret.Handle("POST", "/api/:version/namespaces/:namespace/secrets", _dummyHandler)
|
||||
roleCheckSecret.Handle("GET", "/api/:version/namespaces/:namespace/secrets", _dummyHandler)
|
||||
roleCheckSecret.Handle("GET", "/api/:version/secrets", _dummyHandler)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// GetRoleCheck check the given method and URL matches
|
||||
func GetRoleCheck(method, url string) bool {
|
||||
h, _, _ := roleCheck.Lookup(method, url)
|
||||
return h != nil
|
||||
}
|
||||
|
||||
// GetRoleCheck check the given method and URL matches
|
||||
func GetSecretRoleCheck(method, url string) bool {
|
||||
h, _, _ := roleCheckSecret.Lookup(method, url)
|
||||
return h != nil
|
||||
}
|
||||
|
||||
//GetUserSession get the user session
|
||||
func GetUserSession(skey string) (*UserSession, bool) {
|
||||
hkey := getUserCacheKey(skey)
|
||||
if val, ok := userSessions.Get(hkey); ok {
|
||||
return val.(*UserSession), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
//AddUserSession add user session
|
||||
func AddUserSession(s *UserSession, skey string) {
|
||||
hkey := getUserCacheKey(skey)
|
||||
userSessions.SetWithTTL(hkey, s, 100, time.Minute*15)
|
||||
}
|
||||
|
||||
//DeleteUserSession add user session
|
||||
func DeleteUserSession(skey string) {
|
||||
hkey := getUserCacheKey(skey)
|
||||
userSessions.Del(hkey)
|
||||
}
|
||||
|
||||
//UpdateUserSessionExpiry set a short TTL when error happens
|
||||
func UpdateUserSessionExpiry(skey string, secs int) {
|
||||
hkey := getUserCacheKey(skey)
|
||||
if val, ok := userSessions.Get(hkey); ok {
|
||||
s := val.(*UserSession)
|
||||
if !s.ErrorFlag {
|
||||
s.ErrorFlag = true
|
||||
userSessions.Del(hkey)
|
||||
userSessions.SetWithTTL(hkey, s, 100, time.Second*time.Duration(secs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//SetSessionErrorFlag ser session errflg
|
||||
func SetSessionErrorFlag(skey string) {
|
||||
hkey := getUserCacheKey(skey)
|
||||
if val, ok := userSessions.Get(hkey); ok {
|
||||
s := val.(*UserSession)
|
||||
if !s.ErrorFlag {
|
||||
s.ErrorFlag = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//getUserCacheKey get cache key
|
||||
func getUserCacheKey(skey string) (key uint64) {
|
||||
hasher := _hashPool.Get().(hash.Hash64)
|
||||
hasher.Reset()
|
||||
hasher.Write([]byte(skey))
|
||||
key = hasher.Sum64()
|
||||
_hashPool.Put(hasher)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
package follower
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
const (
|
||||
bufSize = 4 * 1024
|
||||
peekSize = 1024
|
||||
)
|
||||
|
||||
var (
|
||||
_ = fmt.Print
|
||||
)
|
||||
|
||||
type Line struct {
|
||||
bytes []byte
|
||||
discarded int
|
||||
}
|
||||
|
||||
func (l *Line) Bytes() []byte {
|
||||
return l.bytes
|
||||
}
|
||||
|
||||
func (l *Line) String() string {
|
||||
return string(l.bytes)
|
||||
}
|
||||
|
||||
func (l *Line) Discarded() int {
|
||||
return l.discarded
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Offset int64
|
||||
Whence int
|
||||
Reopen bool
|
||||
}
|
||||
|
||||
type Follower struct {
|
||||
once sync.Once
|
||||
file *os.File
|
||||
filename string
|
||||
lines chan Line
|
||||
err error
|
||||
config Config
|
||||
reader *bufio.Reader
|
||||
watcher *fsnotify.Watcher
|
||||
offset int64
|
||||
closeCh chan struct{}
|
||||
}
|
||||
|
||||
func New(filename string, config Config) (*Follower, error) {
|
||||
t := &Follower{
|
||||
filename: filename,
|
||||
lines: make(chan Line),
|
||||
config: config,
|
||||
closeCh: make(chan struct{}),
|
||||
}
|
||||
|
||||
err := t.reopen()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go t.once.Do(t.run)
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (t *Follower) Lines() chan Line {
|
||||
return t.lines
|
||||
}
|
||||
|
||||
func (t *Follower) Err() error {
|
||||
return t.err
|
||||
}
|
||||
|
||||
func (t *Follower) Close() {
|
||||
t.closeCh <- struct{}{}
|
||||
}
|
||||
|
||||
func (t *Follower) run() {
|
||||
t.close(t.follow())
|
||||
}
|
||||
|
||||
func (t *Follower) follow() error {
|
||||
_, err := t.file.Seek(t.config.Offset, t.config.Whence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
eventChan = make(chan fsnotify.Event)
|
||||
errChan = make(chan error, 1)
|
||||
)
|
||||
|
||||
t.watcher, err = fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer t.watcher.Close()
|
||||
go t.watchFileEvents(eventChan, errChan)
|
||||
|
||||
t.watcher.Add(t.filename)
|
||||
|
||||
for {
|
||||
for {
|
||||
// discard leading NUL bytes
|
||||
var discarded int
|
||||
|
||||
for {
|
||||
b, _ := t.reader.Peek(peekSize)
|
||||
i := bytes.LastIndexByte(b, '\x00')
|
||||
|
||||
if i > 0 {
|
||||
n, _ := t.reader.Discard(i + 1)
|
||||
discarded += n
|
||||
}
|
||||
|
||||
if i+1 < peekSize {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
s, err := t.reader.ReadBytes('\n')
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
// if we encounter EOF before a line delimiter,
|
||||
// ReadBytes() will return the remaining bytes,
|
||||
// so push them back onto the buffer, rewind
|
||||
// our seek position, and wait for further file changes.
|
||||
// we also have to save our dangling byte count in the event
|
||||
// that we want to re-open the file and seek to the end
|
||||
if err == io.EOF {
|
||||
l := len(s)
|
||||
|
||||
t.offset, err = t.file.Seek(-int64(l), io.SeekCurrent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.reader.Reset(t.file)
|
||||
break
|
||||
}
|
||||
|
||||
t.sendLine(s, discarded)
|
||||
}
|
||||
|
||||
// we're now at EOF, so wait for changes
|
||||
select {
|
||||
case evt := <-eventChan:
|
||||
switch evt.Op {
|
||||
|
||||
// as soon as something is written, go back and read until EOF.
|
||||
case fsnotify.Chmod:
|
||||
fallthrough
|
||||
|
||||
case fsnotify.Write:
|
||||
fi, err := t.file.Stat()
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// it's possible that an unlink can cause fsnotify.Chmod,
|
||||
// so attempt to rewatch if the file is missing
|
||||
if err := t.rewatch(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// file was truncated, seek to the beginning
|
||||
if t.offset > fi.Size() {
|
||||
t.offset, err = t.file.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.reader.Reset(t.file)
|
||||
}
|
||||
|
||||
continue
|
||||
|
||||
// if a file is removed or renamed
|
||||
// and re-opening is desired, see if it appears
|
||||
// again within a 1 second deadline. this should be enough time
|
||||
// to see the file again for log rotation programs with this behavior
|
||||
default:
|
||||
if !t.config.Reopen {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := t.rewatch(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// any errors that come from fsnotify
|
||||
case err := <-errChan:
|
||||
return err
|
||||
|
||||
// a request to stop
|
||||
case <-t.closeCh:
|
||||
t.watcher.Remove(t.filename)
|
||||
return nil
|
||||
|
||||
// fall back to 10 second polling if we haven't received any fsevents
|
||||
// stat the file, if it's still there, just continue and try to read bytes
|
||||
// if not, go through our re-opening routine
|
||||
case <-time.After(10 * time.Second):
|
||||
fi1, err := t.file.Stat()
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
fi2, err := os.Stat(t.filename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
if os.SameFile(fi1, fi2) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := t.rewatch(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (t *Follower) rewatch() error {
|
||||
t.watcher.Remove(t.filename)
|
||||
if err := t.reopen(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.watcher.Add(t.filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Follower) reopen() error {
|
||||
if t.file != nil {
|
||||
t.file.Close()
|
||||
t.file = nil
|
||||
}
|
||||
|
||||
file, err := os.Open(t.filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.file = file
|
||||
t.reader = bufio.NewReaderSize(t.file, bufSize)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Follower) close(err error) {
|
||||
t.err = err
|
||||
|
||||
if t.file != nil {
|
||||
t.file.Close()
|
||||
}
|
||||
|
||||
close(t.lines)
|
||||
}
|
||||
|
||||
func (t *Follower) sendLine(l []byte, d int) {
|
||||
t.lines <- Line{l[:len(l)-1], d}
|
||||
}
|
||||
|
||||
func (t *Follower) watchFileEvents(eventChan chan fsnotify.Event, errChan chan error) {
|
||||
for {
|
||||
select {
|
||||
case evt, ok := <-t.watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// debounce write events, but send all others
|
||||
switch evt.Op {
|
||||
case fsnotify.Write:
|
||||
select {
|
||||
case eventChan <- evt:
|
||||
default:
|
||||
}
|
||||
|
||||
default:
|
||||
select {
|
||||
case eventChan <- evt:
|
||||
case err := <-t.watcher.Errors:
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// die on a file watching error
|
||||
case err := <-t.watcher.Errors:
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package tail
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/sentry/cryptoutil"
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/sentry/register"
|
||||
sentryrpc "github.com/RafaySystems/rcloud-base/components/common/proto/rpc/sentry"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
)
|
||||
|
||||
// prepare config for outside relay boot strapping
|
||||
func prepareConfigCSRForBootStrapOutSideCore(config *register.Config, CN string) error {
|
||||
privKey, err := cryptoutil.GenerateECDSAPrivateKey()
|
||||
if err != nil {
|
||||
_log.Infow("failed generate private key", "CN", CN)
|
||||
return err
|
||||
}
|
||||
|
||||
key, err := cryptoutil.EncodePrivateKey(privKey, cryptoutil.NoPassword)
|
||||
if err != nil {
|
||||
_log.Infow("failed encode ecd private key", "cn", CN, "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
config.PrivateKey = key
|
||||
|
||||
csr, err := cryptoutil.CreateCSR(pkix.Name{
|
||||
CommonName: CN,
|
||||
Country: []string{"USA"},
|
||||
Organization: []string{"Rafay Systems Inc"},
|
||||
OrganizationalUnit: []string{config.Name},
|
||||
Province: []string{"California"},
|
||||
Locality: []string{"Sunnyvale"},
|
||||
}, privKey)
|
||||
if err != nil {
|
||||
_log.Infow("failed to create CSR", "CN", CN, "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
config.CSR = csr
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerRelayPeerService will register with rafay-sentry-peering-client template token
|
||||
// registration fetches client-certificate/root-ca to connect to sentry peer service
|
||||
func registerRelayPeerService(ctx context.Context) (*register.Config, error) {
|
||||
cfg := ®ister.Config{
|
||||
ClientID: "tail-" + podName,
|
||||
Name: "tail-" + podName,
|
||||
Mode: "client",
|
||||
}
|
||||
|
||||
if bootstrapAddr != "" {
|
||||
// outside core bootstrap
|
||||
cfg.Addr = bootstrapAddr
|
||||
if relayPeeringToken == "" {
|
||||
return nil, fmt.Errorf("empty peering token for bootstrap")
|
||||
}
|
||||
cfg.TemplateToken = relayPeeringToken
|
||||
cfg.Scheme = "http"
|
||||
// check port is 443 then set scheme as https
|
||||
if utils.IsHTTPS(bootstrapAddr) {
|
||||
cfg.Scheme = "https"
|
||||
}
|
||||
// this is a client certificate CN is same as ClientID
|
||||
err := prepareConfigCSRForBootStrapOutSideCore(cfg, cfg.ClientID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed in config csr for relay peering bootstrap")
|
||||
}
|
||||
} else {
|
||||
cfg.TemplateToken = "template/-"
|
||||
cfg.Addr = sentryAddr
|
||||
cfg.Scheme = "grpc"
|
||||
cfg.TemplateName = "rafay-sentry-peering-client"
|
||||
}
|
||||
|
||||
if err := register.Register(ctx, cfg); err != nil {
|
||||
_log.Infow("unable to register", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_log.Infow("successfully registered", "cert", string(cfg.Certificate))
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func newSentryAuthorizationPool(ctx context.Context) (sentryrpc.SentryAuthorizationPool, error) {
|
||||
|
||||
cfg, err := registerRelayPeerService(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
url, err := url.Parse(relayPeeringURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sentryrpc.NewSentryAuthorizationPool(
|
||||
sentryrpc.WithAddr(url.Host),
|
||||
sentryrpc.WithClientCertPEM(cfg.Certificate),
|
||||
sentryrpc.WithClientKeyPEM(cfg.PrivateKey),
|
||||
sentryrpc.WithCaCertPEM(cfg.CACertificate),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package tail
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/segmentio/encoding/json"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
auditPathEnv = "AUDIT_PATH"
|
||||
podNameEnv = "POD_NAME"
|
||||
podNamespaceEnv = "POD_NAMESPACE"
|
||||
peerServiceURIEnv = "RAFAY_RELAY_PEERSERVICE"
|
||||
sentryAddrEnv = "SENTRY_ADDR" // used by relay running inside core
|
||||
bootstrapAddrEnv = "BOOTSTRAP_ADDR"
|
||||
relayPeeringTokenEnv = "RELAY_PEERING_TOKEN"
|
||||
)
|
||||
|
||||
var (
|
||||
podName string
|
||||
podNamespace string
|
||||
relayPeeringURI string
|
||||
sentryAddr string // used by relay running inside core
|
||||
auditPath string
|
||||
|
||||
// for relays running outside of core
|
||||
relayPeeringToken string
|
||||
bootstrapAddr string
|
||||
)
|
||||
|
||||
func setupTail() error {
|
||||
// Enable VIPER to read Environment Variables
|
||||
viper.AutomaticEnv()
|
||||
|
||||
viper.SetDefault(podNameEnv, "relay-pod")
|
||||
viper.SetDefault(podNamespace, "rafay-system")
|
||||
viper.SetDefault(peerServiceURIEnv, "https://peering.sentry.rafay.local:10001")
|
||||
viper.SetDefault(sentryAddrEnv, "localhost:10000")
|
||||
|
||||
// for relays running outside of core
|
||||
viper.SetDefault(bootstrapAddrEnv, "")
|
||||
viper.SetDefault(relayPeeringTokenEnv, "-")
|
||||
viper.SetDefault(auditPathEnv, "/tmp")
|
||||
|
||||
viper.BindEnv(podNameEnv)
|
||||
viper.BindEnv(podNamespaceEnv)
|
||||
viper.BindEnv(relayPeeringTokenEnv)
|
||||
viper.BindEnv(sentryAddrEnv)
|
||||
|
||||
// outside core configs
|
||||
viper.BindEnv(bootstrapAddrEnv)
|
||||
|
||||
podName = viper.GetString(podNameEnv)
|
||||
podNamespace = viper.GetString(podNamespaceEnv)
|
||||
sentryAddr = viper.GetString(sentryAddrEnv)
|
||||
auditPath = viper.GetString(auditPathEnv)
|
||||
|
||||
relayPeeringURI = viper.GetString(peerServiceURIEnv)
|
||||
|
||||
// outside core relay configurations
|
||||
bootstrapAddr = viper.GetString(bootstrapAddrEnv)
|
||||
|
||||
if sentryAddr == "" && bootstrapAddr == "" {
|
||||
_log.Infow("missing sentry & bootstrap uri, please set one of the environment variable RAFAY_SENTRY[relay deployed inside core] (or) BOOTSTRAP_ADDR[outside core]")
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
|
||||
if bootstrapAddr != "" {
|
||||
// outside config found, unset inside boostrap endpoint.
|
||||
// both cannot be set, only one mode is possible
|
||||
sentryAddr = ""
|
||||
}
|
||||
|
||||
if relayPeeringURI == "" {
|
||||
_log.Infow("missing relay peer service uri, please set RAFAY_RELAY_PEERSERVICE environment variable")
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
|
||||
relayPeeringToken = viper.GetString(relayPeeringTokenEnv)
|
||||
|
||||
_log.Infow(
|
||||
"relay server setup values",
|
||||
"podName", podName,
|
||||
"podNamespace", podNamespace,
|
||||
"relayPeeringURI", relayPeeringURI,
|
||||
"auditPath", auditPath,
|
||||
)
|
||||
|
||||
if sentryAddr != "" {
|
||||
_log.Infow("relay inside core", "sentryAddr", sentryAddr)
|
||||
} else {
|
||||
_log.Infow("outside core relay", "bootStrapURI", bootstrapAddr,
|
||||
"relayPeeringToken", relayPeeringToken,
|
||||
)
|
||||
if relayPeeringToken == "-" {
|
||||
_log.Infow("missing env variable", "RELAY_PEERING_TOKEN", relayPeeringToken)
|
||||
return fmt.Errorf("relay server failed in setupserver")
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runTail(ctx context.Context) {
|
||||
sap, err := newSentryAuthorizationPool(ctx)
|
||||
if err != nil {
|
||||
_log.Panicw("unable to create sentry authorization pool", "error", err)
|
||||
}
|
||||
|
||||
//_log.Infow("created sentry authorization pool")
|
||||
|
||||
transformer, err := NewTransformer(sap)
|
||||
if err != nil {
|
||||
_log.Panicw("unable to create transformer", "error", err)
|
||||
}
|
||||
|
||||
//_log.Infow("created audit transformer")
|
||||
|
||||
logChan := make(chan LogMsg)
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second * 30)
|
||||
defer ticker.Stop()
|
||||
|
||||
watchedDir := make(map[string]context.CancelFunc)
|
||||
var m sync.Mutex
|
||||
|
||||
// find new dirs in audit path
|
||||
for ; true; <-ticker.C {
|
||||
//_log.Infow("ticker started")
|
||||
// check if context is done
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_log.Infow("context done")
|
||||
for _, c := range watchedDir {
|
||||
c()
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
|
||||
staleDirs, err := findStaleDirs(auditPath)
|
||||
if err != nil {
|
||||
_log.Infow("unable to find state directories", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
remStaleLoop:
|
||||
for _, staleDir := range staleDirs {
|
||||
err := os.RemoveAll(staleDir)
|
||||
if err != nil {
|
||||
_log.Infow("unable to remove stale dir", "error", err)
|
||||
continue remStaleLoop
|
||||
}
|
||||
}
|
||||
|
||||
dirs, err := findLogDirs(auditPath)
|
||||
if err != nil {
|
||||
_log.Infow("unable to find log dirs", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
//_log.Infow("found log dirs", "dirs", dirs)
|
||||
|
||||
for _, dir := range dirs {
|
||||
m.Lock()
|
||||
|
||||
if _, ok := watchedDir[dir]; !ok {
|
||||
wCtx, cancel := context.WithCancel(ctx)
|
||||
watchedDir[dir] = cancel
|
||||
|
||||
go tailDir(wCtx, dir, logChan)
|
||||
}
|
||||
m.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
transformLoop:
|
||||
for {
|
||||
select {
|
||||
case lm := <-logChan:
|
||||
var am AuditMsg
|
||||
err := transformer.Transform(&lm, &am)
|
||||
if err != nil {
|
||||
_log.Infow("unable to transform message", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = json.NewEncoder(os.Stdout).Encode(&am)
|
||||
if err != nil {
|
||||
_log.Infow("unable to encode audit msg", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
break transformLoop
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RunRelayTail runs relay tail
|
||||
func RunRelayTail(ctx context.Context) {
|
||||
setupTail()
|
||||
runTail(ctx)
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
package tail
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/log"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/tail/follower"
|
||||
)
|
||||
|
||||
const (
|
||||
filterName = "lines.cuckoo"
|
||||
)
|
||||
|
||||
var (
|
||||
_log = log.GetLogger()
|
||||
)
|
||||
|
||||
func isStaleDir(path string) bool {
|
||||
autitLogPath := fmt.Sprintf("%s/audit.log", path)
|
||||
info, err := os.Stat(autitLogPath)
|
||||
if err != nil {
|
||||
_log.Infow("unable to stat file", "path", autitLogPath, "error", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// delete directory that has no modified files in last 7 days.
|
||||
if info.ModTime().Before(time.Now().Add(-time.Hour * 24 * 7)) {
|
||||
_log.Infow("audit log not updated for 7 days", "path", autitLogPath)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func hasLogs(path string) bool {
|
||||
|
||||
matches, _ := filepath.Glob(fmt.Sprintf("%s/audit*.log", path))
|
||||
|
||||
return len(matches) > 0
|
||||
}
|
||||
|
||||
func findStaleDirs(root string) ([]string, error) {
|
||||
if !strings.HasSuffix(root, "/") {
|
||||
root = root + "/"
|
||||
}
|
||||
|
||||
var staleDirs []string
|
||||
var nonStaleDirs []string
|
||||
|
||||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
_log.Infow("prevent panic by handling failure in accessing the path", path, "error", err)
|
||||
return err
|
||||
}
|
||||
if info.IsDir() && hasLogs(path) {
|
||||
if isStaleDir(path) {
|
||||
staleDirs = append(staleDirs, path)
|
||||
} else {
|
||||
nonStaleDirs = append(nonStaleDirs, path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(nonStaleDirs) <= 0 {
|
||||
// looks like all are stale directories, there are no logs for
|
||||
// 7 days hence can't identify which one to delete.
|
||||
// skip stale directory cleanup for now.
|
||||
return nil, fmt.Errorf("can not identify stale vs non-stale directory")
|
||||
}
|
||||
|
||||
return staleDirs, nil
|
||||
}
|
||||
|
||||
func findLogDirs(root string) ([]string, error) {
|
||||
|
||||
if !strings.HasSuffix(root, "/") {
|
||||
root = root + "/"
|
||||
}
|
||||
|
||||
var auditDirs []string
|
||||
|
||||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
_log.Infow("prevent panic by handling failure in accessing the path", path, "error", err)
|
||||
return err
|
||||
}
|
||||
if info.IsDir() && hasLogs(path) && !isStaleDir(path) {
|
||||
auditDirs = append(auditDirs, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return auditDirs, nil
|
||||
}
|
||||
|
||||
func tailRotatedFile(ctx context.Context, filePath string, tailChan chan<- LogMsg) error {
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
limiter := rate.NewLimiter(rate.Every(time.Minute/200), 200)
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
|
||||
for scanner.Scan() {
|
||||
|
||||
err := limiter.Wait(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var lm LogMsg
|
||||
err = json.Unmarshal(scanner.Bytes(), &lm)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
tailChan <- lm
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// remove the file after done reading
|
||||
os.Remove(filePath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tailCurrentFile(ctx context.Context, filePath string, tailChan chan<- LogMsg) error {
|
||||
|
||||
t, err := follower.New(filePath, follower.Config{
|
||||
Whence: io.SeekStart,
|
||||
Offset: 0,
|
||||
Reopen: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
limiter := rate.NewLimiter(rate.Every(time.Minute/200), 200)
|
||||
|
||||
for line := range t.Lines() {
|
||||
|
||||
err := limiter.Wait(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var lm LogMsg
|
||||
err = json.Unmarshal(line.Bytes(), &lm)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
tailChan <- lm
|
||||
|
||||
}
|
||||
|
||||
if t.Err() != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// tailDir tails audit log directory for a relay pod
|
||||
func tailDir(ctx context.Context, path string, logChan chan<- LogMsg) error {
|
||||
|
||||
// filter, err := getFilter(path)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// defer saveFilter(path, filter)
|
||||
|
||||
files := func() []string {
|
||||
matches, _ := filepath.Glob(fmt.Sprintf("%s/audit*.log", path))
|
||||
|
||||
sort.Strings(matches)
|
||||
return matches
|
||||
}()
|
||||
|
||||
//_log.Infow("found files", "files", files)
|
||||
|
||||
tailChan := make(chan LogMsg)
|
||||
for _, file := range files {
|
||||
if strings.HasSuffix(file, "audit.log") {
|
||||
go tailCurrentFile(ctx, file, tailChan)
|
||||
} else {
|
||||
go tailRotatedFile(ctx, file, tailChan)
|
||||
}
|
||||
}
|
||||
|
||||
tailLoop:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break tailLoop
|
||||
case log := <-tailChan:
|
||||
|
||||
// // if the log xid is seen already ignore
|
||||
// if filter.Lookup(lm.XID.Bytes()) {
|
||||
// filter.Delete(lm.XID.Bytes())
|
||||
// continue
|
||||
// }
|
||||
|
||||
// filter.InsertUnique(lm.XID.Bytes())
|
||||
logChan <- log
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
package tail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"hash"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"github.com/jinzhu/inflection"
|
||||
"github.com/twmb/murmur3"
|
||||
|
||||
sentryrpc "github.com/RafaySystems/rcloud-base/components/common/proto/rpc/sentry"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
var _dummyHandler = func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {}
|
||||
|
||||
var _bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
var _hashPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return murmur3.New64()
|
||||
},
|
||||
}
|
||||
|
||||
func getCacheKey(s string) uint64 {
|
||||
hasher := _hashPool.Get().(hash.Hash64)
|
||||
defer _hashPool.Put(hasher)
|
||||
|
||||
buf := _bufPool.Get().(*bytes.Buffer)
|
||||
defer _bufPool.Put(buf)
|
||||
|
||||
buf.Reset()
|
||||
buf.WriteString(s)
|
||||
|
||||
hasher.Reset()
|
||||
hasher.Write(buf.Bytes())
|
||||
return hasher.Sum64()
|
||||
}
|
||||
|
||||
// Transformer is the interface for transforming relay log message into audit message
|
||||
type Transformer interface {
|
||||
Transform(lm *LogMsg, am *AuditMsg) error
|
||||
}
|
||||
|
||||
// NewTransformer returns new relay log transformer
|
||||
func NewTransformer(authzPool sentryrpc.SentryAuthorizationPool) (Transformer, error) {
|
||||
|
||||
r := httprouter.New()
|
||||
|
||||
r.Handle("GET", "/api", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version/:kind0", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version/:kind0/:namespace", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version/:kind0/:namespace/:kind1", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version/:kind0/:namespace/:kind1/:name", _dummyHandler)
|
||||
r.Handle("GET", "/apis", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version/:kind0", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version/:kind0/:namespace", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version/:kind0/:namespace/:kind1", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version/:kind0/:namespace/:kind1/:name", _dummyHandler)
|
||||
|
||||
cache, err := ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1e4, // Num keys to track frequency of (10k).
|
||||
MaxCost: 1 << 27, // Maximum cost of cache (128MB).
|
||||
BufferItems: 64, // Number of keys per Get buffer.
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := &transformer{
|
||||
authzPool: authzPool,
|
||||
r: r,
|
||||
cache: cache,
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
type transformer struct {
|
||||
authzPool sentryrpc.SentryAuthorizationPool
|
||||
cache *ristretto.Cache
|
||||
r *httprouter.Router
|
||||
}
|
||||
|
||||
func (t *transformer) getUser(cn string) (*sentryrpc.LookupUserResponse, error) {
|
||||
key := getCacheKey(cn)
|
||||
if val, ok := t.cache.Get(key); ok {
|
||||
if usr, ok := val.(*sentryrpc.LookupUserResponse); ok {
|
||||
return usr, nil
|
||||
}
|
||||
}
|
||||
|
||||
// cache miss
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
|
||||
authzClient, err := t.authzPool.NewClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer authzClient.Close()
|
||||
|
||||
resp, err := authzClient.LookupUser(ctx, &sentryrpc.LookupUserRequest{
|
||||
UserCN: cn,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.cache.Set(key, resp, 100)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (t *transformer) getCluster(serverName string) (*sentryrpc.LookupClusterResponse, error) {
|
||||
idx := strings.Index(serverName, ".")
|
||||
|
||||
if idx > 0 {
|
||||
key := getCacheKey(serverName[0:idx])
|
||||
if val, ok := t.cache.Get(key); ok {
|
||||
if cluster, ok := val.(*sentryrpc.LookupClusterResponse); ok {
|
||||
return cluster, nil
|
||||
}
|
||||
}
|
||||
|
||||
// cache miss
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
|
||||
authzClient, err := t.authzPool.NewClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer authzClient.Close()
|
||||
|
||||
resp, err := authzClient.LookupCluster(ctx, &sentryrpc.LookupClusterRequest{
|
||||
ClusterSNI: serverName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.cache.Set(key, resp, 110)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid serverName %s", serverName)
|
||||
}
|
||||
|
||||
func (t *transformer) getParams(url string) httprouter.Params {
|
||||
|
||||
if h, params, _ := t.r.Lookup("GET", url); h != nil {
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *transformer) Transform(lm *LogMsg, am *AuditMsg) error {
|
||||
|
||||
//_log.Infow("transforming", "logMessage", *lm)
|
||||
cluster, err := t.getCluster(lm.ServerName)
|
||||
if err != nil {
|
||||
_log.Infow("unable to lookup cluster", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
user, err := t.getUser(lm.User)
|
||||
if err != nil {
|
||||
_log.Infow("unable to lookup user", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
params := t.getParams(lm.URL)
|
||||
|
||||
am.ClusterName = cluster.Name
|
||||
am.OrganizationID = user.OrganizationID
|
||||
am.PartnerID = user.PartnerID
|
||||
am.UserName = user.UserName
|
||||
am.Duration = lm.Duration
|
||||
am.Written = lm.Written
|
||||
am.Timestamp = lm.Timestamp
|
||||
am.Method = lm.Method
|
||||
am.URL = lm.URL
|
||||
am.Query = lm.Query
|
||||
am.XID = lm.XID
|
||||
am.StatusCode = lm.StatusCode
|
||||
am.RemoteAddr = lm.RemoteAddr
|
||||
am.SessionType = user.SessionType
|
||||
|
||||
if params != nil {
|
||||
am.APIVersion = fmt.Sprintf("%s/%s", params.ByName("group"), params.ByName("version"))
|
||||
if params.ByName("kind1") != "" {
|
||||
am.Kind = params.ByName("kind1")
|
||||
} else {
|
||||
am.Kind = params.ByName("kind0")
|
||||
}
|
||||
am.Kind = inflection.Singular(am.Kind)
|
||||
am.Namespace = params.ByName("namespace")
|
||||
am.Name = params.ByName("name")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package tail
|
||||
|
||||
import (
|
||||
"github.com/rs/xid"
|
||||
)
|
||||
|
||||
// {
|
||||
// "level": "info",
|
||||
// "ts": 1591154299.638035,
|
||||
// "msg": "audit",
|
||||
// "xid": "brbhcuug10lf2qfjj1hg",
|
||||
// "method": "GET",
|
||||
// "url": "/apis/metrics.k8s.io/v1beta1?timeout=32s",
|
||||
// "serverName": "x3mxvkr.user.relay.rafay.local",
|
||||
// "user": "rafay-core-debug",
|
||||
// "remoteAddr": "127.0.0.1:63513",
|
||||
// "statusCode": 503,
|
||||
// "written": 20,
|
||||
// "duration": 0.002513407
|
||||
// }
|
||||
|
||||
// LogMsg represents log message
|
||||
type LogMsg struct {
|
||||
//Level string `json:"level"`
|
||||
//Message string `json:"msg"`
|
||||
Timestamp string `json:"ts"`
|
||||
XID xid.ID `json:"xid"`
|
||||
Method string `json:"method"`
|
||||
URL string `json:"url"`
|
||||
Query string `json:"query"`
|
||||
ServerName string `json:"serverName"`
|
||||
User string `json:"user"`
|
||||
RemoteAddr string `json:"remoteAddr"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
Written int64 `json:"written"`
|
||||
Duration float64 `json:"duration"`
|
||||
}
|
||||
|
||||
// AuditMsg represents audit message
|
||||
type AuditMsg struct {
|
||||
Timestamp string `json:"ts"`
|
||||
XID xid.ID `json:"id"`
|
||||
StatusCode int `json:"sc"`
|
||||
UserName string `json:"un"`
|
||||
OrganizationID string `json:"o"`
|
||||
PartnerID string `json:"p"`
|
||||
RemoteAddr string `json:"ra"`
|
||||
Duration float64 `json:"d"`
|
||||
ClusterName string `json:"cn"`
|
||||
APIVersion string `json:"av"`
|
||||
Kind string `json:"k"`
|
||||
Namespace string `json:"ns"`
|
||||
Name string `json:"n"`
|
||||
Method string `json:"m"`
|
||||
URL string `json:"url"`
|
||||
Query string `json:"q"`
|
||||
Written int64 `json:"w"`
|
||||
SessionType string `json:"st"`
|
||||
}
|
||||
|
||||
// Reset resets audit message
|
||||
func (m *AuditMsg) Reset() {
|
||||
m.Timestamp = ""
|
||||
m.XID = xid.NilID()
|
||||
m.StatusCode = 0
|
||||
m.UserName = ""
|
||||
m.OrganizationID = ""
|
||||
m.PartnerID = ""
|
||||
m.RemoteAddr = ""
|
||||
m.Duration = 0
|
||||
m.ClusterName = ""
|
||||
m.APIVersion = ""
|
||||
m.Kind = ""
|
||||
m.Namespace = ""
|
||||
m.Name = ""
|
||||
m.Method = ""
|
||||
m.URL = ""
|
||||
m.Query = ""
|
||||
m.Written = 0
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package tail
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
// CASE 1 /api
|
||||
// CASE 2 /apis
|
||||
// CASE 3 /apis/storage.k8s.io/v1beta1
|
||||
// CASE 4 /api/v1/namespaces
|
||||
// CASE 5 /api/v1/pods
|
||||
// CASE 6 /api/v1/namespaces/rafay-system
|
||||
// CASE 7 /api/v1/namespaces/rafay-system/configmaps/relay-agent-config
|
||||
// CASE 8 /apis/k3s.cattle.io/v1/namespaces/kube-system/addons
|
||||
|
||||
func TestURL(t *testing.T) {
|
||||
r := httprouter.New()
|
||||
|
||||
r.Handle("GET", "/api", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version/:kind0", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version/:kind0/:namespace", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version/:kind0/:namespace/:kind1", _dummyHandler)
|
||||
r.Handle("GET", "/api/:version/:kind0/:namespace/:kind1/:name", _dummyHandler)
|
||||
r.Handle("GET", "/apis", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version/:kind0", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version/:kind0/:namespace", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version/:kind0/:namespace/:kind1", _dummyHandler)
|
||||
r.Handle("GET", "/apis/:group/:version/:kind0/:namespace/:kind1/:name", _dummyHandler)
|
||||
|
||||
if h, params, _ := r.Lookup("GET", "/api/v1/pods"); h != nil {
|
||||
t.Log(params)
|
||||
} else {
|
||||
t.Error("expected match")
|
||||
return
|
||||
}
|
||||
|
||||
if h, params, _ := r.Lookup("GET", "/apis/storage.k8s.io/v1beta1"); h != nil {
|
||||
t.Log(params)
|
||||
} else {
|
||||
t.Error("expected match")
|
||||
return
|
||||
}
|
||||
|
||||
if h, params, _ := r.Lookup("GET", "/api/v1/namespaces/rafay-system/configmaps/relay-agent-config"); h != nil {
|
||||
t.Log(params)
|
||||
} else {
|
||||
t.Error("expected match")
|
||||
return
|
||||
}
|
||||
|
||||
if h, params, _ := r.Lookup("GET", "/apis/k3s.cattle.io/v1/namespaces/kube-system/addons"); h != nil {
|
||||
t.Log(params)
|
||||
} else {
|
||||
t.Error("expected match")
|
||||
return
|
||||
}
|
||||
|
||||
if h, params, _ := r.Lookup("GET", "/apis/metrics.k8s.io/v1beta1"); h != nil {
|
||||
t.Log(params)
|
||||
} else {
|
||||
t.Error("expected match")
|
||||
return
|
||||
}
|
||||
|
||||
if h, params, _ := r.Lookup("GET", "/api/v1/namespaces/test-ns"); h != nil {
|
||||
t.Log(params)
|
||||
} else {
|
||||
t.Error("expected match")
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"hash"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/log"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/controller/apply"
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/grpc"
|
||||
sentryrpc "github.com/RafaySystems/rcloud-base/components/common/proto/rpc/sentry"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/proxy"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"github.com/twmb/murmur3"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/transport"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
)
|
||||
|
||||
var (
|
||||
_log = log.GetLogger()
|
||||
)
|
||||
|
||||
const (
|
||||
bypassNamespace = "rafay-system"
|
||||
)
|
||||
|
||||
var bypassUserNames = []string{"system-sa", "default"}
|
||||
|
||||
func getClusterID(sni string) (string, error) {
|
||||
idx := strings.Index(sni, ".")
|
||||
if idx < 0 {
|
||||
return "", fmt.Errorf("invalid user sni format %s", sni)
|
||||
}
|
||||
return sni[0:idx], nil
|
||||
}
|
||||
|
||||
type bypassWrapper struct {
|
||||
sni, key, bypassUserName string
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
func (w *bypassWrapper) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
r.Header.Set("X-Rafay-User", w.bypassUserName)
|
||||
r.Header.Set("X-Rafay-Key", w.key)
|
||||
r.Header.Set("X-Rafay-Namespace", bypassNamespace)
|
||||
|
||||
if !strings.HasSuffix(r.URL.Path, "/") {
|
||||
r.URL.Path = r.URL.Path + "/"
|
||||
}
|
||||
|
||||
return w.rt.RoundTrip(r)
|
||||
}
|
||||
|
||||
func newBypassWrapper(sni, key, bypassUserName string) transport.WrapperFunc {
|
||||
return func(rt http.RoundTripper) http.RoundTripper {
|
||||
return &bypassWrapper{sni: sni, key: key, rt: rt, bypassUserName: bypassUserName}
|
||||
}
|
||||
}
|
||||
|
||||
func getKubeRESTConfig(socketPath, sni, dialinLookupKey, username string) *rest.Config {
|
||||
|
||||
cfg := &rest.Config{
|
||||
Host: fmt.Sprintf("%s_%s", sni, dialinLookupKey),
|
||||
// Set transport expicitly to prevent client for caching transport
|
||||
Transport: &http.Transport{
|
||||
DialContext: proxy.UnixDialContext(socketPath, dialinLookupKey, username, sni),
|
||||
},
|
||||
Timeout: time.Second * 5,
|
||||
}
|
||||
|
||||
cfg.Wrap(newBypassWrapper(sni, dialinLookupKey, username))
|
||||
|
||||
return cfg
|
||||
|
||||
}
|
||||
|
||||
var _hashPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
// The Pool's New function should generally only return pointer
|
||||
// types, since a pointer can be put into the return interface
|
||||
// value without an allocation:
|
||||
return murmur3.New64()
|
||||
},
|
||||
}
|
||||
|
||||
type authzProvisioner struct {
|
||||
clientCache *ristretto.Cache
|
||||
authzCache *ristretto.Cache
|
||||
}
|
||||
|
||||
func newAuthzProvisioner() (*authzProvisioner, error) {
|
||||
clientCache, err := ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1e4, // Num keys to track frequency of (10k).
|
||||
MaxCost: 1 << 27, // Maximum cost of cache (256MB).
|
||||
BufferItems: 64, // Number of keys per Get buffer.
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authzCache, err := ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1e4, // Num keys to track frequency of (10k).
|
||||
MaxCost: 1 << 25, // Maximum cost of cache (32MB).
|
||||
BufferItems: 64, // Number of keys per Get buffer.
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &authzProvisioner{clientCache: clientCache, authzCache: authzCache}, nil
|
||||
}
|
||||
|
||||
func (p *authzProvisioner) getClient(socketPath, sni, dialinLookupKey string) (client.Client, error) {
|
||||
|
||||
key := func() uint64 {
|
||||
hasher := _hashPool.Get().(hash.Hash64)
|
||||
hasher.Reset()
|
||||
hasher.Write([]byte(sni))
|
||||
hasher.Write([]byte(dialinLookupKey))
|
||||
k := hasher.Sum64()
|
||||
_hashPool.Put(hasher)
|
||||
return k
|
||||
}()
|
||||
|
||||
if i, ok := p.clientCache.Get(key); ok {
|
||||
if c, ok := i.(client.Client); ok {
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
getK8sClient := func(bypassUserName string) (client.Client, error) {
|
||||
cfg := getKubeRESTConfig(socketPath, sni, dialinLookupKey, bypassUserName)
|
||||
mapper, err := apiutil.NewDynamicRESTMapper(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := client.New(cfg, client.Options{Scheme: scheme.Scheme, Mapper: mapper})
|
||||
return c, err
|
||||
}
|
||||
|
||||
var c client.Client
|
||||
var err error
|
||||
for _, username := range bypassUserNames {
|
||||
c, err = getK8sClient(username)
|
||||
if err != nil {
|
||||
_log.Infow("error getting k8s client for username", "username", username)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.clientCache.SetWithTTL(key, c, 100, time.Minute*30)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (p *authzProvisioner) getAuthz(ctx context.Context, userCN, sni string, certIssue int64) (*sentryrpc.GetUserAuthorizationResponse, error) {
|
||||
clusterID, err := getClusterID(sni)
|
||||
if err != nil {
|
||||
_log.Infow("unable to get clusterID", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, err := url.Parse(utils.PeerServiceURI)
|
||||
if err != nil {
|
||||
_log.Infow("unable to parse peer service url", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
//Load certificates
|
||||
tlsConfig, err := ClientTLSConfigFromBytes(utils.PeerCertificate, utils.PeerPrivateKey, utils.PeerCACertificate, u.Host)
|
||||
if err != nil {
|
||||
_log.Infow("unable to build tls config for peer service", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
transportCreds := credentials.NewTLS(tlsConfig)
|
||||
peerSeviceHost := u.Host
|
||||
|
||||
conn, err := grpc.NewSecureClientConn(ctx, peerSeviceHost, transportCreds)
|
||||
if err != nil {
|
||||
_log.Infow("unable to connect to sentry", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := sentryrpc.NewClusterAuthorizationClient(conn)
|
||||
|
||||
resp, err := client.GetUserAuthorization(ctx, &sentryrpc.GetUserAuthorizationRequest{
|
||||
UserCN: userCN,
|
||||
ClusterID: clusterID,
|
||||
CertIssueSeconds: certIssue,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
_log.Infow("unable to get authorization for user", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (p *authzProvisioner) provisionAuthzHandleRoleChange(auth *sentryrpc.GetUserAuthorizationResponse, socketPath, sni, dialinLookupKey string) {
|
||||
k8sDelClient, err := p.getClient(socketPath, sni, dialinLookupKey)
|
||||
if err != nil {
|
||||
_log.Infow("unable to get del client", "sni", sni, "dialinLookupKey", dialinLookupKey, "error", err)
|
||||
return
|
||||
}
|
||||
nctx, cancel := context.WithTimeout(context.Background(), time.Second*180)
|
||||
defer cancel()
|
||||
// Delete cluster role binding to clean if exist to handle change in user role
|
||||
for _, crb := range auth.DeleteClusterRoleBindings {
|
||||
//crbo, _, err := runtime.ToObject(crb)
|
||||
if err == nil {
|
||||
err := k8sDelClient.Delete(nctx, crb)
|
||||
if err != nil {
|
||||
_log.Debugw("unable to delete ClusterRoleBindings", "name", crb.TypeMeta.GetObjectKind(), "obj", crb, "err", err)
|
||||
} else {
|
||||
_log.Infow("successfully to deleted ClusterRoleBindings", "obj", crb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To handle change in namespace changes delete rolebindings to clean if exist.
|
||||
for _, rb := range auth.DeleteRoleBindings {
|
||||
//rbo, _, err := runtime.ToObject(rb)
|
||||
if err == nil {
|
||||
err := k8sDelClient.Delete(nctx, rb)
|
||||
if err != nil {
|
||||
_log.Debugw("unable to delete RoleBindings", "name", rb.TypeMeta.GetObjectKind(), "obj", rb, "err", err)
|
||||
} else {
|
||||
_log.Infow("successfully to deleted RoleBindings", "obj", rb)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *authzProvisioner) provisionAuthz(ctx context.Context, auth *sentryrpc.GetUserAuthorizationResponse, socketPath, sni, dialinLookupKey string) error {
|
||||
|
||||
k8sClient, err := p.getClient(socketPath, sni, dialinLookupKey)
|
||||
if err != nil {
|
||||
_log.Infow("unable to get client", "sni", sni, "dialinLookupKey", dialinLookupKey, "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Handle deletion of excluded clusterrolebindings and rolebindings
|
||||
// in the background.
|
||||
go p.provisionAuthzHandleRoleChange(auth, socketPath, sni, dialinLookupKey)
|
||||
if len(auth.ClusterRoles) > 0 {
|
||||
_log.Infow("cluster scope authz for", "user", auth.ServiceAccount, "ClusterRoles", auth.ClusterRoles, "ClusterRoleBindings", auth.ClusterRoleBindings)
|
||||
}
|
||||
if len(auth.Roles) > 0 {
|
||||
_log.Infow("namespace scope authz for", "user", auth.ServiceAccount, "Roles", auth.Roles, "RoleBindings", auth.RoleBindings, "Namespaces", auth.Namespaces)
|
||||
}
|
||||
|
||||
applier := apply.NewApplier(k8sClient)
|
||||
|
||||
/*sao, _, err := runtime.ToObject(auth.ServiceAccount)
|
||||
if err != nil {
|
||||
_log.Infow("unable to make service account runtime object", "error", err)
|
||||
return err
|
||||
}*/
|
||||
|
||||
err = applier.Apply(ctx, auth.ServiceAccount)
|
||||
// Ignore already exist error caused due to
|
||||
// multiple inflight request trying to provision
|
||||
// ZTKA JIT service account
|
||||
if err != nil && !strings.Contains(err.Error(), "already exists") {
|
||||
_log.Infow("unable to apply service account", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, clusterRole := range auth.ClusterRoles {
|
||||
/*cro, _, err := runtime.ToObject(clusterRole)
|
||||
if err != nil {
|
||||
_log.Infow("unable to make clusterRole runtime object", "error", err)
|
||||
return err
|
||||
}*/
|
||||
|
||||
err = applier.Apply(ctx, clusterRole)
|
||||
if err != nil && !strings.Contains(err.Error(), "already exists") {
|
||||
_log.Infow("unable to apply clusterRole", "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, clusterRoleBinding := range auth.ClusterRoleBindings {
|
||||
/*crbo, _, err := runtime.ToObject(clusterRoleBinding)
|
||||
if err != nil {
|
||||
_log.Infow("unable to make clusterRoleBinding runtime object", "error", err)
|
||||
return err
|
||||
}*/
|
||||
|
||||
err = applier.Apply(ctx, clusterRoleBinding)
|
||||
if err != nil && !strings.Contains(err.Error(), "already exists") {
|
||||
_log.Infow("unable to apply clusterRoleBinding", "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, role := range auth.Roles {
|
||||
/*cro, _, err := runtime.ToObject(role)
|
||||
if err != nil {
|
||||
_log.Infow("unable to make roles runtime object", "error", err)
|
||||
return err
|
||||
}*/
|
||||
|
||||
err = applier.Apply(ctx, role)
|
||||
if err != nil && !strings.Contains(err.Error(), "already exists") {
|
||||
_log.Infow("unable to apply Role", "error", err)
|
||||
//Ignore any error
|
||||
}
|
||||
}
|
||||
|
||||
for _, roleBinding := range auth.RoleBindings {
|
||||
/*crbo, _, err := runtime.ToObject(roleBinding)
|
||||
if err != nil {
|
||||
_log.Infow("unable to make RoleBinding runtime object", "error", err)
|
||||
return err
|
||||
}*/
|
||||
|
||||
err = applier.Apply(ctx, roleBinding)
|
||||
if err != nil && !strings.Contains(err.Error(), "already exists") {
|
||||
_log.Infow("unable to apply RoleBinding", "error", err)
|
||||
//Ignore any error
|
||||
}
|
||||
}
|
||||
|
||||
_log.Infow("applied authz", "sni", sni, "user", auth.UserName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type provisionedUser struct {
|
||||
UserName string
|
||||
Role string
|
||||
IsReadRole bool
|
||||
IsOrgAdmin bool
|
||||
EnforceOrgAdminOnlySecretAccess bool
|
||||
}
|
||||
|
||||
func (p *authzProvisioner) ProvisionAuthzForUser(socketPath, userCN, sni, dialinLookupKey string, forceProvision, refreshSession bool, certIssue int64) (string, string, bool, bool, bool, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*60)
|
||||
defer cancel()
|
||||
|
||||
key := func() uint64 {
|
||||
hasher := _hashPool.Get().(hash.Hash64)
|
||||
hasher.Reset()
|
||||
hasher.Write([]byte(userCN))
|
||||
hasher.Write([]byte(sni))
|
||||
k := hasher.Sum64()
|
||||
_hashPool.Put(hasher)
|
||||
return k
|
||||
}()
|
||||
|
||||
if !forceProvision {
|
||||
if i, ok := p.authzCache.Get(key); ok {
|
||||
if pu, ok := i.(*provisionedUser); ok {
|
||||
return pu.UserName, pu.Role, pu.IsReadRole, pu.IsOrgAdmin, pu.EnforceOrgAdminOnlySecretAccess, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := p.getAuthz(ctx, userCN, sni, certIssue)
|
||||
if err != nil {
|
||||
return "", "", false, false, false, err
|
||||
}
|
||||
|
||||
applyctx, applycancel := context.WithTimeout(context.Background(), time.Second*60)
|
||||
defer applycancel()
|
||||
err = p.provisionAuthz(applyctx, resp, socketPath, sni, dialinLookupKey)
|
||||
// ignore cluster provision failures during refresh.
|
||||
// continue with existing RBAC.
|
||||
if !refreshSession && err != nil {
|
||||
return "", "", false, false, false, err
|
||||
}
|
||||
|
||||
p.authzCache.SetWithTTL(key, &provisionedUser{
|
||||
UserName: resp.UserName,
|
||||
Role: resp.RoleName,
|
||||
IsReadRole: resp.IsRead,
|
||||
IsOrgAdmin: resp.IsOrgAdmin,
|
||||
EnforceOrgAdminOnlySecretAccess: resp.EnforceOrgAdminOnlySecretAccess,
|
||||
}, 100, time.Minute*5)
|
||||
|
||||
return resp.UserName, resp.RoleName, resp.IsRead, resp.IsOrgAdmin, resp.EnforceOrgAdminOnlySecretAccess, nil
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package tunnel
|
||||
|
||||
import "time"
|
||||
|
||||
// Backoff defines behavior of staggering reconnection retries.
|
||||
type Backoff interface {
|
||||
// Next returns the duration to sleep before retrying to reconnect.
|
||||
// If the returned value is negative, the retry is aborted.
|
||||
NextBackOff() time.Duration
|
||||
|
||||
// Reset is used to signal a reconnection was successful and next
|
||||
// call to Next should return desired time duration for 1st reconnection
|
||||
// attempt.
|
||||
Reset()
|
||||
}
|
||||
@@ -0,0 +1,651 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/proxy"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
"github.com/cenkalti/backoff"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
//ClientConfig ..
|
||||
type ClientConfig struct {
|
||||
//ServiceName name of the service
|
||||
ServiceName string
|
||||
// ServerAddr specifies address of the tunnel server.
|
||||
ServerAddr string
|
||||
//Upstream upstream address
|
||||
Upstream string
|
||||
//Protocol ..
|
||||
Protocol string
|
||||
// TLSClientConfig specifies the tls configuration to use with
|
||||
// tls.Client.
|
||||
TLSClientConfig *tls.Config
|
||||
// Backoff specifies backoff policy on server connection retry. If nil
|
||||
// when dial fails it will not be retried.
|
||||
Backoff Backoff
|
||||
|
||||
//ServiceProxy is Func responsible for transferring data between server and local services.
|
||||
ServiceProxy proxy.Func
|
||||
// Logger is optional logger. If nil logging is disabled.
|
||||
Logger *relaylogger.RelayLog
|
||||
}
|
||||
|
||||
//Client struct
|
||||
type Client struct {
|
||||
sync.Mutex
|
||||
conn net.Conn
|
||||
httpServer *http2.Server
|
||||
serverErr error
|
||||
lastDisconnect time.Time
|
||||
config *ClientConfig
|
||||
logger *relaylogger.RelayLog
|
||||
closeChnl chan bool
|
||||
streams int64
|
||||
lastRequest time.Time
|
||||
lastRequestStreams int64
|
||||
isScaledConnection bool
|
||||
}
|
||||
|
||||
var (
|
||||
clog *relaylogger.RelayLog
|
||||
//Clients map, key by ServerName
|
||||
//Clients = make(map[string]*Client)
|
||||
ScaleClients = make(chan bool, 5)
|
||||
)
|
||||
|
||||
func expBackoff(c BackoffConfig) *backoff.ExponentialBackOff {
|
||||
b := backoff.NewExponentialBackOff()
|
||||
b.InitialInterval = c.Interval
|
||||
b.Multiplier = c.Multiplier
|
||||
b.MaxInterval = c.MaxInterval
|
||||
b.MaxElapsedTime = c.MaxTime
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
//loadNewRelayNetwork start the relay agent for a given network
|
||||
func loadNewRelayNetwork(ctx context.Context, rnc utils.RelayNetworkConfig) error {
|
||||
var spxy proxy.Func
|
||||
var tlsconf *tls.Config
|
||||
var dialout *Dialout
|
||||
var err error
|
||||
|
||||
backoff := BackoffConfig{
|
||||
Interval: DefaultBackoffInterval,
|
||||
Multiplier: DefaultBackoffMultiplier,
|
||||
MaxInterval: DefaultBackoffMaxInterval,
|
||||
MaxTime: DefaultBackoffMaxTime,
|
||||
}
|
||||
|
||||
//proxy handler
|
||||
switch rnc.Network.Name {
|
||||
case utils.CDAGENTCORE:
|
||||
tlsconf, err = ClientTLSConfigFromBytes(rnc.RelayAgentCert, rnc.RelayAgentKey, rnc.RelayAgentCACert, strings.ReplaceAll(rnc.Network.Domain, "*", utils.AgentID))
|
||||
if err != nil {
|
||||
clog.Error(
|
||||
err,
|
||||
"failed to create tlsconfig",
|
||||
"service name", rnc.Network.Name,
|
||||
"addr", rnc.Network.Domain,
|
||||
)
|
||||
return fmt.Errorf("failed to load client certs")
|
||||
}
|
||||
dialout = &Dialout{
|
||||
Protocol: rnc.Network.Name,
|
||||
Upstream: rnc.Network.Upstream,
|
||||
Addr: strings.ReplaceAll(rnc.Network.Domain, "*", utils.AgentID),
|
||||
ServiceSNI: utils.AgentID,
|
||||
}
|
||||
spxy = clientProxy(utils.GENTCP, dialout, clog.WithName(rnc.Network.Name))
|
||||
default:
|
||||
tlsconf, err = ClientTLSConfigFromBytes(rnc.RelayAgentCert, rnc.RelayAgentKey, rnc.RelayAgentCACert, strings.ReplaceAll(rnc.Network.Domain, "*", utils.ClusterID))
|
||||
if err != nil {
|
||||
clog.Error(
|
||||
err,
|
||||
"failed to create tlsconfig",
|
||||
"service name", rnc.Network.Name,
|
||||
"addr", rnc.Network.Domain,
|
||||
)
|
||||
return fmt.Errorf("failed to load client certs")
|
||||
}
|
||||
dialout = &Dialout{
|
||||
Protocol: rnc.Network.Name,
|
||||
Upstream: rnc.Network.Upstream,
|
||||
Addr: strings.ReplaceAll(rnc.Network.Domain, "*", utils.ClusterID),
|
||||
ServiceSNI: utils.ClusterID,
|
||||
}
|
||||
spxy = clientProxy(utils.KUBECTL, dialout, clog.WithName(rnc.Network.Name))
|
||||
}
|
||||
|
||||
if spxy == nil {
|
||||
return fmt.Errorf("failed to load client proxy")
|
||||
}
|
||||
|
||||
ccfg := &ClientConfig{
|
||||
ServiceName: rnc.Network.Name,
|
||||
ServerAddr: dialout.Addr,
|
||||
Protocol: dialout.Protocol,
|
||||
TLSClientConfig: tlsconf,
|
||||
Upstream: dialout.Upstream,
|
||||
ServiceProxy: spxy,
|
||||
Backoff: expBackoff(backoff),
|
||||
Logger: clog.WithName(rnc.Network.Name),
|
||||
}
|
||||
|
||||
for i := 0; i < utils.MaxDials; i++ {
|
||||
c := &Client{
|
||||
config: ccfg,
|
||||
httpServer: &http2.Server{},
|
||||
logger: clog.WithName(rnc.Network.Name),
|
||||
isScaledConnection: false,
|
||||
}
|
||||
|
||||
c.closeChnl = make(chan bool)
|
||||
go c.runClient(ctx)
|
||||
}
|
||||
|
||||
// scale clients
|
||||
// based on rate of new streams or
|
||||
// based on total concurrent streams
|
||||
go runClientScaling(ctx, ccfg, rnc)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runClientScaling(ctx context.Context, ccfg *ClientConfig, rnc utils.RelayNetworkConfig) {
|
||||
var scaledClients []*Client
|
||||
totalScaledClient := 0
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ScaleClients:
|
||||
// got signal to scale
|
||||
if totalScaledClient < utils.MaxDials*utils.MaxScaleMultiplier {
|
||||
c := &Client{
|
||||
config: ccfg,
|
||||
httpServer: &http2.Server{},
|
||||
logger: clog.WithName(rnc.Network.Name),
|
||||
isScaledConnection: true,
|
||||
}
|
||||
c.closeChnl = make(chan bool)
|
||||
scaledClients = append(scaledClients, c)
|
||||
totalScaledClient++
|
||||
go c.runClient(ctx)
|
||||
clog.Info(
|
||||
"scale client signal",
|
||||
" totalScaledClient ", totalScaledClient,
|
||||
)
|
||||
}
|
||||
case <-time.After(5 * time.Minute):
|
||||
tempClients := scaledClients[:0]
|
||||
for _, c := range scaledClients {
|
||||
now := time.Now()
|
||||
c.Lock()
|
||||
curStreams := atomic.LoadInt64(&c.streams)
|
||||
d := now.Sub(c.lastRequest)
|
||||
s := int64(d / time.Hour)
|
||||
if curStreams <= 0 && s >= int64(utils.HealingInterval) {
|
||||
// no request for last 24Hr, close client
|
||||
c.closeChnl <- true
|
||||
totalScaledClient--
|
||||
} else {
|
||||
tempClients = append(tempClients, c)
|
||||
}
|
||||
c.Unlock()
|
||||
}
|
||||
scaledClients = tempClients
|
||||
clog.Info(
|
||||
"scaled client timer",
|
||||
" totalScaledClient ", totalScaledClient,
|
||||
)
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) runClient(ctx context.Context) {
|
||||
if err := c.Start(ctx); err != nil {
|
||||
if c.isScaledConnection {
|
||||
c.logger.Info(
|
||||
"closed scaled dialouts after idle time",
|
||||
"service name", c.config.ServiceName,
|
||||
"addr", c.config.ServerAddr,
|
||||
)
|
||||
} else {
|
||||
c.logger.Error(
|
||||
err,
|
||||
"failed to start client for dialouts",
|
||||
"service name", c.config.ServiceName,
|
||||
"addr", c.config.ServerAddr,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Start relay client
|
||||
func (c *Client) Start(ctx context.Context) error {
|
||||
cw := make(chan bool)
|
||||
|
||||
for {
|
||||
conn, err := c.connect()
|
||||
if err != nil {
|
||||
c.logger.Info(
|
||||
"connect failed will retry after 2 sec",
|
||||
)
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
go func() {
|
||||
//handles the http/2 tunnel
|
||||
c.httpServer.ServeConn(conn, &http2.ServeConnOpts{
|
||||
Handler: http.HandlerFunc(c.serveHTTP),
|
||||
})
|
||||
|
||||
cw <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-cw:
|
||||
// dialout got closed
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
case <-c.closeChnl:
|
||||
c.conn.Close()
|
||||
c.logger.Info(
|
||||
"close connection due to idle streams",
|
||||
)
|
||||
return fmt.Errorf("idle streams")
|
||||
case <-ctx.Done():
|
||||
c.conn.Close()
|
||||
return fmt.Errorf("ctx done")
|
||||
}
|
||||
|
||||
c.logger.Info(
|
||||
"client disconnected",
|
||||
)
|
||||
c.Lock()
|
||||
now := time.Now()
|
||||
err = c.serverErr
|
||||
|
||||
// detect disconnect hiccup
|
||||
if err == nil && now.Sub(c.lastDisconnect).Seconds() < 5 {
|
||||
err = fmt.Errorf("connection is being cut")
|
||||
}
|
||||
|
||||
c.conn = nil
|
||||
c.serverErr = nil
|
||||
c.lastDisconnect = now
|
||||
c.Unlock()
|
||||
|
||||
if err != nil {
|
||||
c.logger.Error(
|
||||
err,
|
||||
"disconnected, will retry after 2 sec",
|
||||
"name", c.config.ServiceName,
|
||||
)
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) processDialoutProxy(conn net.Conn, network, addr string) error {
|
||||
// send CONNECT addr HTTP/1.1 header
|
||||
connHeader := "CONNECT " + addr + " HTTP/1.1\r\nHost: " + addr + "\r\n"
|
||||
if utils.DialoutProxyAuth != "" {
|
||||
connHeader = connHeader + "Proxy-Authorization:" + utils.DialoutProxyAuth + "\r\n"
|
||||
}
|
||||
connHeader = connHeader + "Connection: Keep-Alive\r\n\r\n"
|
||||
|
||||
conn.Write([]byte(connHeader))
|
||||
tmp := make([]byte, 1)
|
||||
checkHeader := ""
|
||||
startAppend := false
|
||||
respData := ""
|
||||
for {
|
||||
n, err := conn.Read(tmp)
|
||||
if n != 1 || err != nil {
|
||||
c.logger.Info(
|
||||
"dial failed ",
|
||||
"proxy", utils.DialoutProxy,
|
||||
"proxy header", connHeader,
|
||||
"network", network,
|
||||
"checkHeader", checkHeader,
|
||||
"err", err,
|
||||
)
|
||||
return fmt.Errorf("proxy read error")
|
||||
}
|
||||
respData += string(tmp[0])
|
||||
if tmp[0] == '\r' {
|
||||
if startAppend {
|
||||
checkHeader += string(tmp[0])
|
||||
} else {
|
||||
checkHeader = "\r"
|
||||
startAppend = true
|
||||
}
|
||||
} else if tmp[0] == '\n' {
|
||||
if startAppend {
|
||||
if checkHeader == "\r\n\r" {
|
||||
// prased the proxy response header
|
||||
break
|
||||
}
|
||||
checkHeader += string(tmp)
|
||||
}
|
||||
} else {
|
||||
startAppend = false
|
||||
checkHeader = ""
|
||||
}
|
||||
}
|
||||
c.logger.Info(
|
||||
"proxy dialout success",
|
||||
"proxy resp", respData,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
//dialout connect
|
||||
func (c *Client) connect() (net.Conn, error) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
if c.conn != nil {
|
||||
return nil, fmt.Errorf("already connected")
|
||||
}
|
||||
|
||||
conn, err := c.dial()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to server %s error %s", c.config.ServerAddr, err)
|
||||
}
|
||||
c.conn = conn
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
//dial
|
||||
func (c *Client) dial() (net.Conn, error) {
|
||||
var (
|
||||
network = "tcp"
|
||||
addr = c.config.ServerAddr
|
||||
tlsConfig = c.config.TLSClientConfig
|
||||
)
|
||||
|
||||
doDial := func() (conn net.Conn, err error) {
|
||||
|
||||
d := &net.Dialer{
|
||||
Timeout: 60 * time.Second,
|
||||
}
|
||||
if utils.DialoutProxy == "" {
|
||||
conn, err = d.Dial(network, addr)
|
||||
} else {
|
||||
conn, err = d.Dial(network, utils.DialoutProxy)
|
||||
if err == nil {
|
||||
err = c.processDialoutProxy(conn, network, addr)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
err = utils.KeepAlive(conn)
|
||||
}
|
||||
if err == nil {
|
||||
conn = tls.Client(conn, tlsConfig)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
err = conn.(*tls.Conn).Handshake()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
conn = nil
|
||||
}
|
||||
|
||||
c.logger.Info(
|
||||
"dial failed",
|
||||
"network", network,
|
||||
"addr", addr,
|
||||
"err", err,
|
||||
)
|
||||
}
|
||||
|
||||
c.logger.Info(
|
||||
"action dial out",
|
||||
"network", network,
|
||||
"addr", addr,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
b := c.config.Backoff
|
||||
if b == nil {
|
||||
// try once and return
|
||||
return doDial()
|
||||
}
|
||||
|
||||
for {
|
||||
|
||||
conn, err := doDial()
|
||||
|
||||
// success
|
||||
if err == nil {
|
||||
b.Reset()
|
||||
c.logger.Info(
|
||||
"dial success",
|
||||
)
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// failure
|
||||
d := b.NextBackOff()
|
||||
if d < 0 {
|
||||
b.Reset()
|
||||
return conn, fmt.Errorf("backoff limit exeded: %s", err)
|
||||
}
|
||||
|
||||
// backoff
|
||||
c.logger.Info(
|
||||
"action backoff",
|
||||
"sleep", d,
|
||||
"address", c.config.ServerAddr,
|
||||
)
|
||||
time.Sleep(d)
|
||||
}
|
||||
}
|
||||
|
||||
// tunnel serveHTTP handler. Requests form relay lands here.
|
||||
// request handled based on the action in the ctrl message (header)
|
||||
// Connect method is used as handshake
|
||||
// PUT method is used for tunneled requests that carry
|
||||
// stream data as req.Body
|
||||
func (c *Client) serveHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
c.logger.Debug(
|
||||
"invoked handler serveHTTP",
|
||||
"method", r.Method,
|
||||
"currentStreams", atomic.LoadInt64(&c.streams),
|
||||
)
|
||||
|
||||
if r.Method == http.MethodConnect {
|
||||
if r.Header.Get(utils.HeaderError) != "" {
|
||||
c.handleHandshakeError(w, r)
|
||||
} else {
|
||||
c.handleHandshake(w, r)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
atomic.AddInt64(&c.streams, 1)
|
||||
defer atomic.AddInt64(&c.streams, ^int64(0))
|
||||
|
||||
curStreams := atomic.LoadInt64(&c.streams)
|
||||
now := time.Now()
|
||||
|
||||
c.Lock()
|
||||
d := now.Sub(c.lastRequest)
|
||||
s := int64(d / time.Second)
|
||||
if s >= 4 { // check in minimum 4 sec
|
||||
if !c.isScaledConnection {
|
||||
if curStreams > int64(utils.ScalingStreamsThreshold) {
|
||||
// concurrent streams count is high
|
||||
ScaleClients <- true
|
||||
} else if curStreams > c.lastRequestStreams {
|
||||
rate := (curStreams - c.lastRequestStreams) / s
|
||||
if rate > int64(utils.ScalingStreamsRateThreshold) {
|
||||
// rate of new stream is high
|
||||
ScaleClients <- true
|
||||
}
|
||||
}
|
||||
}
|
||||
c.lastRequest = now
|
||||
c.lastRequestStreams = curStreams
|
||||
}
|
||||
c.Unlock()
|
||||
|
||||
msg, err := utils.ReadControlMessage(r)
|
||||
if err != nil {
|
||||
c.logger.Error(
|
||||
err,
|
||||
"Read Control Message failed",
|
||||
)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
c.logger.Debug(
|
||||
"handle proxy action",
|
||||
"ctrlMsg", msg,
|
||||
"req", r,
|
||||
"currentStreams", atomic.LoadInt64(&c.streams),
|
||||
)
|
||||
|
||||
switch msg.Action {
|
||||
case utils.ActionProxy:
|
||||
c.config.ServiceProxy(w, r.Body, msg, r)
|
||||
default:
|
||||
c.logger.Info(
|
||||
"unknown action",
|
||||
"ctrlMsg", msg,
|
||||
)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleHandshakeError(w http.ResponseWriter, r *http.Request) {
|
||||
err := fmt.Errorf(r.Header.Get(utils.HeaderError))
|
||||
|
||||
c.logger.Info(
|
||||
"action handshake error",
|
||||
"addr", r.RemoteAddr,
|
||||
"err", err,
|
||||
)
|
||||
|
||||
c.Lock()
|
||||
c.serverErr = fmt.Errorf("server error: %s", err)
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
func (c *Client) handleHandshake(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
c.logger.Info(
|
||||
"action", "handshake",
|
||||
"addr", r.RemoteAddr,
|
||||
)
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
host, _, _ := net.SplitHostPort(c.config.ServerAddr)
|
||||
msg := handShakeMsg{
|
||||
ServiceName: c.config.ServiceName,
|
||||
Protocol: c.config.Protocol,
|
||||
Host: host,
|
||||
}
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
c.logger.Info(
|
||||
"msg", "handshake failed",
|
||||
"err", err,
|
||||
)
|
||||
return
|
||||
}
|
||||
w.Write(b)
|
||||
}
|
||||
|
||||
//setups the proxy func handler
|
||||
func clientProxy(svcName string, d *Dialout, logger *relaylogger.RelayLog) proxy.Func {
|
||||
proxyCfg := &utils.ProxyConfig{
|
||||
Protocol: d.Protocol,
|
||||
Addr: d.Addr,
|
||||
ServiceSNI: d.ServiceSNI,
|
||||
RootCA: d.RootCA,
|
||||
ClientCRT: d.ClientCRT,
|
||||
ClientKEY: d.ClientKEY,
|
||||
Upstream: d.Upstream,
|
||||
UpstreamClientCRT: d.UpstreamClientCRT,
|
||||
UpstreamClientKEY: d.UpstreamClientKEY,
|
||||
UpstreamRootCA: d.UpstreamRootCA,
|
||||
UpstreamSkipVerify: d.UpstreamSkipVerify,
|
||||
UpstreamKubeConfig: d.UpstreamKubeConfig,
|
||||
Version: d.Version,
|
||||
}
|
||||
|
||||
switch svcName {
|
||||
case utils.KUBECTL:
|
||||
if p := proxy.NewKubeCtlTCPProxy(logger.WithName("TCPProxy"), proxyCfg); p != nil {
|
||||
return p.Proxy
|
||||
}
|
||||
logger.Error(
|
||||
nil,
|
||||
"proxy.NewKubeCtlTCPProxy returned nil",
|
||||
)
|
||||
return nil
|
||||
case utils.GENTCP:
|
||||
if p := proxy.NewTCPProxy(logger.WithName("TCPProxy"), proxyCfg); p != nil {
|
||||
return p.Proxy
|
||||
}
|
||||
logger.Error(
|
||||
nil,
|
||||
"proxy.NewTCPProxy returned nil",
|
||||
)
|
||||
return nil
|
||||
default:
|
||||
logger.Error(
|
||||
nil,
|
||||
"unknown service name",
|
||||
)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//StartClient starts relay clients
|
||||
func StartClient(ctx context.Context, log *relaylogger.RelayLog, file string, rnc utils.RelayNetworkConfig, exitChan chan<- bool) {
|
||||
clog = log.WithName("Client")
|
||||
|
||||
if err := loadNewRelayNetwork(ctx, rnc); err != nil {
|
||||
clog.Error(err, "failed to load relay network")
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
clog.Error(
|
||||
ctx.Err(),
|
||||
"Stopping client",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Default backoff configuration.
|
||||
const (
|
||||
DefaultBackoffInterval = 500 * time.Millisecond
|
||||
DefaultBackoffMultiplier = 1.5
|
||||
DefaultBackoffMaxInterval = 20 * time.Second
|
||||
DefaultBackoffMaxTime = 2 * time.Minute
|
||||
)
|
||||
|
||||
// BackoffConfig defines behavior of staggering reconnection retries.
|
||||
type BackoffConfig struct {
|
||||
Interval time.Duration
|
||||
Multiplier float64
|
||||
MaxInterval time.Duration
|
||||
MaxTime time.Duration
|
||||
}
|
||||
|
||||
// Dialout defines the dialout.
|
||||
type Dialout struct {
|
||||
Protocol string
|
||||
Addr string
|
||||
ServiceSNI string
|
||||
RootCA string
|
||||
ClientCRT string
|
||||
ClientKEY string
|
||||
Upstream string
|
||||
UpstreamClientCRT string
|
||||
UpstreamClientKEY string
|
||||
UpstreamRootCA string
|
||||
UpstreamSkipVerify bool
|
||||
UpstreamKubeConfig string
|
||||
Version string
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
//UNIXSOCKET ..
|
||||
UNIXSOCKET = "/tmp/relay-unix-"
|
||||
)
|
||||
|
||||
func startClient(wg *sync.WaitGroup, buf []byte, t *testing.T) {
|
||||
defer wg.Done()
|
||||
|
||||
fmt.Print("starting client")
|
||||
buf3 := make([]byte, 4096)
|
||||
// connect to this socket
|
||||
socketPath := UNIXSOCKET + "kubectldialin.relay.rafay.dev"
|
||||
conn, err := net.DialTimeout("unix", socketPath, 60*time.Second)
|
||||
if err != nil {
|
||||
t.Error("failed to connect ", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Connected to ", socketPath)
|
||||
|
||||
for {
|
||||
conn.Write(buf)
|
||||
str := "GET /apis/rbac.authorization.k8s.io/v1?timeout=32s HTTP/1.1\r\nHost: 192.168.56.103:6443\r\nUser-Agent: curl/7.54.0\r\nAccept: */*\r\nX-Rafay-User:namespace-admin-sa\r\nX-Rafay-Namespace: default\r\n\r\n"
|
||||
conn.Write([]byte(str))
|
||||
|
||||
conn.SetReadDeadline(time.Now().Add(10 * (time.Second)))
|
||||
|
||||
for {
|
||||
nr, err := conn.Read(buf3)
|
||||
if err != nil {
|
||||
fmt.Println("done reading ", err)
|
||||
return
|
||||
}
|
||||
data := buf3[0:nr]
|
||||
println("Client got:", string(data), nr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRelayClient(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
num := 1
|
||||
key := "cluster1.kubectldialin.relay.rafay.dev-ABCD"
|
||||
|
||||
message := fmt.Sprintf("{\"DialinKey\": \"%s\", \"UserName\": \"namespace-admin-sa\", \"SNI\": \"cluster1.kubectldialin.relay.rafay.dev\"}", key[:len(key)-1])
|
||||
copy(buf, message)
|
||||
|
||||
for i := 0; i < num; i++ {
|
||||
wg.Add(1)
|
||||
fmt.Println("starting client")
|
||||
go startClient(&wg, buf, t)
|
||||
}
|
||||
|
||||
fmt.Print("Waiting for workers")
|
||||
wg.Wait()
|
||||
|
||||
fmt.Print("Completed")
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
)
|
||||
|
||||
type handShakeMsg struct {
|
||||
ServiceName string
|
||||
Protocol string
|
||||
Host string
|
||||
}
|
||||
|
||||
var (
|
||||
//PeerProbeChanel to push cluster connection probe.
|
||||
//The RPC picks the sni and sends to core
|
||||
PeerProbeChanel = make(chan string, 256)
|
||||
emptyID [32]byte
|
||||
)
|
||||
|
||||
//ServerTLSConfigFromBytes prepare a tls config from cert,key,rootCA
|
||||
func ServerTLSConfigFromBytes(certList []utils.SNICertificate, rootCAs []string, nextprotos ...string) (*tls.Config, error) {
|
||||
var err error
|
||||
|
||||
// load certs
|
||||
config := &tls.Config{}
|
||||
config.Certificates = make([]tls.Certificate, len(certList))
|
||||
|
||||
for i, v := range certList {
|
||||
config.Certificates[i], err = tls.X509KeyPair(v.CertFile, v.KeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
config.BuildNameToCertificate()
|
||||
|
||||
// load rootCAs for client authentication
|
||||
clientAuth := tls.RequireAndVerifyClientCert
|
||||
var roots *x509.CertPool
|
||||
if len(rootCAs) > 0 {
|
||||
roots = x509.NewCertPool()
|
||||
|
||||
for _, rootCA := range rootCAs {
|
||||
rootPEM := []byte(rootCA)
|
||||
if len(rootPEM) > 0 {
|
||||
if ok := roots.AppendCertsFromPEM(rootPEM); !ok {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
|
||||
config.ClientAuth = clientAuth
|
||||
config.ClientCAs = roots
|
||||
config.SessionTicketsDisabled = true
|
||||
config.MinVersion = tls.VersionTLS12
|
||||
config.CipherSuites = []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
|
||||
config.PreferServerCipherSuites = true
|
||||
if len(nextprotos) > 0 {
|
||||
config.NextProtos = nextprotos
|
||||
} else {
|
||||
config.NextProtos = []string{"h1", "h2"}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
//ClientTLSConfigFromBytes sets tls config
|
||||
func ClientTLSConfigFromBytes(tlsCrt []byte, tlsKey []byte, rootPEM []byte, addr string) (*tls.Config, error) {
|
||||
cert, err := tls.X509KeyPair(tlsCrt, tlsKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var roots *x509.CertPool
|
||||
if len(rootPEM) > 0 {
|
||||
roots = x509.NewCertPool()
|
||||
if ok := roots.AppendCertsFromPEM(rootPEM); !ok {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
ServerName: host,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
InsecureSkipVerify: roots == nil,
|
||||
RootCAs: roots,
|
||||
SessionTicketsDisabled: true,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
CipherSuites: []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
|
||||
PreferServerCipherSuites: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
//ClientTLSConfig sets tls config
|
||||
func ClientTLSConfig(tlsCrt string, tlsKey string, rootCA string, addr string) (*tls.Config, error) {
|
||||
|
||||
cert, err := tls.LoadX509KeyPair(tlsCrt, tlsKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var roots *x509.CertPool
|
||||
if rootCA != "" {
|
||||
roots = x509.NewCertPool()
|
||||
rootPEM, err := ioutil.ReadFile(rootCA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok := roots.AppendCertsFromPEM(rootPEM); !ok {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
ServerName: host,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
InsecureSkipVerify: roots == nil,
|
||||
RootCAs: roots,
|
||||
SessionTicketsDisabled: true,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
CipherSuites: []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
|
||||
PreferServerCipherSuites: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
//GetRemoteCertID extract peer ID
|
||||
func GetRemoteCertID(conn *tls.Conn) (string, error) {
|
||||
// Try a TLS connection over the given connection. We explicitly perform
|
||||
// the handshake, since we want to maintain the invariant that, if this
|
||||
// function returns successfully, then the connection should be valid
|
||||
// and verified.
|
||||
if err := conn.Handshake(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cs := conn.ConnectionState()
|
||||
|
||||
// We should have exactly one peer certificate.
|
||||
certs := cs.PeerCertificates
|
||||
if cl := len(certs); cl != 1 {
|
||||
return "", fmt.Errorf("expecting 1 peer certificate got %d", cl)
|
||||
}
|
||||
|
||||
// Get remote cert's ID.
|
||||
remoteCert := certs[0]
|
||||
//remoteID := New(remoteCert.Raw)
|
||||
|
||||
return remoteCert.Subject.CommonName, nil
|
||||
}
|
||||
|
||||
func SendPeerProbe(chnl chan<- string, clustersni string) {
|
||||
attempt := 0
|
||||
select {
|
||||
case chnl <- clustersni:
|
||||
return
|
||||
default:
|
||||
attempt++
|
||||
if attempt > 3 {
|
||||
return
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
var _dplog *relaylogger.RelayLog
|
||||
|
||||
type connPair struct {
|
||||
conn net.Conn
|
||||
clientConn *http2.ClientConn
|
||||
}
|
||||
|
||||
type dialinConnector struct {
|
||||
// this is list of dialin peer ids
|
||||
connKeys []string
|
||||
lbIndex int
|
||||
}
|
||||
type dialinPool struct {
|
||||
t *http2.Transport
|
||||
conns map[string]connPair // key is host:port
|
||||
free func(string)
|
||||
mu sync.RWMutex
|
||||
//map of connector IDs with dialin SNI key
|
||||
dialinConnectors map[string]*dialinConnector
|
||||
}
|
||||
|
||||
func newDialinPool(t *http2.Transport, f func(string), log *relaylogger.RelayLog) *dialinPool {
|
||||
return &dialinPool{
|
||||
t: t,
|
||||
free: f,
|
||||
conns: make(map[string]connPair),
|
||||
dialinConnectors: make(map[string]*dialinConnector),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *dialinPool) URL(key string) string {
|
||||
return fmt.Sprint("https://", key)
|
||||
}
|
||||
|
||||
//GetClientConn get connector
|
||||
func (p *dialinPool) GetClientConn(req *http.Request, addr string) (*http2.ClientConn, error) {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
if cp, ok := p.conns[addr]; ok && cp.clientConn.CanTakeNewRequest() {
|
||||
return cp.clientConn, nil
|
||||
}
|
||||
|
||||
return nil, errClientNotConnected
|
||||
}
|
||||
|
||||
// CheckDialinKeyExist check cached key's still exist in pool
|
||||
func (p *dialinPool) CheckDialinKeyExist(key string) bool {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
_, ok := p.conns[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (p *dialinPool) MarkDead(c *http2.ClientConn) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
for addr, cp := range p.conns {
|
||||
if cp.clientConn == c {
|
||||
_dplog.Debug("MarkDead", addr, p)
|
||||
p.close(cp, addr)
|
||||
s := strings.SplitAfter(addr, utils.JoinString)
|
||||
if len(s) == 3 {
|
||||
sni := strings.Trim(s[0], utils.JoinString)
|
||||
addr := s[1] + s[2]
|
||||
if !p.deleteDialinConnectorKey(sni, addr) {
|
||||
_dplog.Error(nil, "error in dialin MarkDead connector key delete did not find key ", addr)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *dialinPool) AddConn(conn net.Conn, identifier string, sni string, remoteAddr string) (string, error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
// append peer-cert-id with remoteAddr
|
||||
addr := p.addr(identifier) + utils.JoinString + remoteAddr
|
||||
|
||||
// prepend dialin sni to addr to construct the key
|
||||
key := sni + utils.JoinString + addr
|
||||
|
||||
if cp, ok := p.conns[key]; ok {
|
||||
// check conns has the key
|
||||
if err := p.ping(cp); err != nil {
|
||||
p.close(cp, key)
|
||||
} else {
|
||||
return "", fmt.Errorf("connector key %s already in dialin pool ", key)
|
||||
}
|
||||
}
|
||||
|
||||
// create transport new connection
|
||||
c, err := p.t.NewClientConn(conn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// add conn to conns
|
||||
p.conns[key] = connPair{
|
||||
conn: conn,
|
||||
clientConn: c,
|
||||
}
|
||||
|
||||
go sendHeartBeats(p.conns[key])
|
||||
|
||||
// set dialinConnectors map using key as sni
|
||||
if item, ok := p.dialinConnectors[sni]; ok {
|
||||
itemCount := len(item.connKeys)
|
||||
if itemCount <= 0 {
|
||||
p.dialinConnectors[sni].connKeys = append(p.dialinConnectors[sni].connKeys, addr)
|
||||
sort.Strings(p.dialinConnectors[sni].connKeys)
|
||||
} else {
|
||||
index := sort.SearchStrings(p.dialinConnectors[sni].connKeys, addr)
|
||||
if index < itemCount && p.dialinConnectors[sni].connKeys[index] == addr {
|
||||
_dplog.Info("address already exist")
|
||||
} else {
|
||||
//item not found
|
||||
p.dialinConnectors[sni].connKeys = append(p.dialinConnectors[sni].connKeys, addr)
|
||||
sort.Strings(p.dialinConnectors[sni].connKeys)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p.dialinConnectors[sni] = &dialinConnector{
|
||||
lbIndex: 0,
|
||||
}
|
||||
p.dialinConnectors[sni].connKeys = append(p.dialinConnectors[sni].connKeys, addr)
|
||||
sort.Strings(p.dialinConnectors[sni].connKeys)
|
||||
}
|
||||
|
||||
_dplog.Info(
|
||||
"Added dialin connection",
|
||||
"addr", addr,
|
||||
"key", key,
|
||||
)
|
||||
return key, nil
|
||||
}
|
||||
|
||||
//GetDialinConnectorKey get connector key
|
||||
func (p *dialinPool) GetDialinConnectorCount(sni string) (int, error) {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
_dplog.Debug(
|
||||
"GetDialinConnectorCount",
|
||||
"sni", sni,
|
||||
"pool", p,
|
||||
)
|
||||
|
||||
_dplog.Info("GetDialinConnectorCount", p.dialinConnectors)
|
||||
if item, ok := p.dialinConnectors[sni]; ok {
|
||||
itemCount := len(item.connKeys)
|
||||
if itemCount > 0 {
|
||||
return itemCount, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("Empty dialin pool.dialinConnectors for sni %s ", sni)
|
||||
}
|
||||
|
||||
func (p *dialinPool) getConnKey(sni string, item *dialinConnector, count int) (string, error) {
|
||||
for i := 0; i < count; i++ {
|
||||
key := sni + utils.JoinString + item.connKeys[i]
|
||||
if _, ok := p.conns[key]; ok {
|
||||
return key, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Empty dialin pool.dialinConnectors for sni %s ", sni)
|
||||
}
|
||||
|
||||
//GetDialinConnectorKey get connector key
|
||||
func (p *dialinPool) GetDialinConnectorKey(sni string) (string, error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
_dplog.Info(
|
||||
"GetDialinConnectorKey",
|
||||
"sni", sni,
|
||||
)
|
||||
|
||||
if item, ok := p.dialinConnectors[sni]; ok {
|
||||
itemCount := len(item.connKeys)
|
||||
|
||||
if itemCount <= 0 {
|
||||
return "", fmt.Errorf("Empty dialin pool.dialinConnectors for sni %s ", sni)
|
||||
}
|
||||
|
||||
//simple round robin selection
|
||||
if item.lbIndex >= itemCount {
|
||||
item.lbIndex = 0
|
||||
}
|
||||
|
||||
key := sni + utils.JoinString + item.connKeys[item.lbIndex]
|
||||
item.lbIndex++
|
||||
|
||||
// check key
|
||||
if _, ok := p.conns[key]; !ok {
|
||||
// get any key
|
||||
return p.getConnKey(sni, item, itemCount)
|
||||
}
|
||||
|
||||
// key is valid
|
||||
return key, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Empty dialin pool.dialinConnectors for sni %s ", sni)
|
||||
}
|
||||
|
||||
func (p *dialinPool) deleteDialinConnectorKey(sni, addr string) bool {
|
||||
if item, ok := p.dialinConnectors[sni]; ok {
|
||||
itemCount := len(item.connKeys)
|
||||
index := sort.SearchStrings(p.dialinConnectors[sni].connKeys, addr)
|
||||
if index < itemCount {
|
||||
// Not expecting lots of connectors. So using slower delete opeartion
|
||||
// by shifting elements to preserve the sorted orders
|
||||
p.dialinConnectors[sni].connKeys = append(item.connKeys[:index], item.connKeys[index+1:]...)
|
||||
_dplog.Info(
|
||||
"Deleted Connnection from dialin pool",
|
||||
"addr", addr,
|
||||
)
|
||||
if len(p.dialinConnectors[sni].connKeys) <= 0 {
|
||||
_dplog.Info(
|
||||
"Deleted last connection from dialin pool",
|
||||
"sni", sni,
|
||||
"addr", addr,
|
||||
)
|
||||
delete(p.dialinConnectors, sni)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *dialinPool) DeleteConn(identifier string, sni string, remoteAddr string) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
// append peer-cert-id with remoteAddr
|
||||
addr := identifier + utils.JoinString + remoteAddr
|
||||
|
||||
// prepend dialin sni to addr to construct the key
|
||||
key := sni + utils.JoinString + addr
|
||||
if cp, ok := p.conns[key]; ok {
|
||||
p.close(cp, key)
|
||||
} else {
|
||||
_dplog.Error(
|
||||
nil,
|
||||
"did not find key in pool.Conns",
|
||||
"key", key,
|
||||
"pool", p,
|
||||
)
|
||||
}
|
||||
|
||||
if p.deleteDialinConnectorKey(sni, addr) {
|
||||
return
|
||||
}
|
||||
|
||||
_dplog.Info(
|
||||
"DeleteConn did not find the coonection",
|
||||
"sni", sni,
|
||||
"addr", addr,
|
||||
"key", key,
|
||||
"pool", p,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
func (p *dialinPool) Ping(identifier string) (time.Duration, error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if cp, ok := p.conns[identifier]; ok {
|
||||
start := time.Now()
|
||||
err := p.ping(cp)
|
||||
return time.Since(start), err
|
||||
}
|
||||
|
||||
return 0, errClientNotConnected
|
||||
}
|
||||
|
||||
// heart beats to keep dialins alive to avoid idletimeout
|
||||
func sendHeartBeats(cp connPair) {
|
||||
for {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), utils.DefaultPingTimeout)
|
||||
if err := cp.clientConn.Ping(ctx); err != nil {
|
||||
cancel()
|
||||
_dplog.Debug("dialin keep-alive ping err", err)
|
||||
return
|
||||
}
|
||||
_dplog.Debug("dialin keep-alive ping success")
|
||||
cancel()
|
||||
time.Sleep(30 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *dialinPool) ping(cp connPair) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), utils.DefaultPingTimeout)
|
||||
defer cancel()
|
||||
|
||||
return cp.clientConn.Ping(ctx)
|
||||
}
|
||||
|
||||
func (p *dialinPool) close(cp connPair, addr string) {
|
||||
cp.conn.Close()
|
||||
_dplog.Info("dialin close", addr)
|
||||
delete(p.conns, addr)
|
||||
if p.free != nil {
|
||||
p.free(addr)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *dialinPool) addr(identifier string) string {
|
||||
return identifier
|
||||
}
|
||||
|
||||
//StartDialinPoolMgr starting dialin connection manager
|
||||
func StartDialinPoolMgr(ctx context.Context, log *relaylogger.RelayLog, exitChan chan<- bool) {
|
||||
_dplog = log.WithName("DialinPool")
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
slog.Error(
|
||||
ctx.Err(),
|
||||
"Stopping dialin pool manager",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//GetDialinMetrics get connector key
|
||||
func (p *dialinPool) GetDialinMetrics(w http.ResponseWriter) {
|
||||
var clusterCnt, connCnt int
|
||||
clusterCnt, connCnt = 0, 0
|
||||
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
_dplog.Info(
|
||||
"GetDialinMetrics",
|
||||
)
|
||||
|
||||
fmt.Fprintf(w, "{\"dialinmetrics\": [")
|
||||
for sni, item := range p.dialinConnectors {
|
||||
clusterCnt++
|
||||
connCnt += len(item.connKeys)
|
||||
itemCount := strconv.Itoa(len(item.connKeys))
|
||||
|
||||
fmt.Fprintf(w, "{\"cluster\": \""+sni+"\", \"connections\": \""+itemCount+"\"},")
|
||||
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "], \"totalclusters\": "+strconv.Itoa(clusterCnt))
|
||||
fmt.Fprintf(w, ", \"totalconnections\": "+strconv.Itoa(connCnt))
|
||||
fmt.Fprintf(w, ", \"podname\": "+utils.PODNAME)
|
||||
|
||||
fmt.Fprintf(w, " }")
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package tunnel
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
errClientNotSubscribed = errors.New("client not subscribed")
|
||||
errClientNotConnected = errors.New("client not connected")
|
||||
errClientAlreadyConnected = errors.New("client already connected")
|
||||
|
||||
errUnauthorised = errors.New("unauthorised")
|
||||
)
|
||||
@@ -0,0 +1,168 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net/url"
|
||||
|
||||
"time"
|
||||
|
||||
comgrpc "github.com/RafaySystems/rcloud-base/components/common/pkg/grpc"
|
||||
peerclient "github.com/RafaySystems/rcloud-base/components/common/pkg/sentry/peering"
|
||||
relayrpc "github.com/RafaySystems/rcloud-base/components/common/proto/rpc/sentry"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/utils"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
var peerlog *relaylogger.RelayLog
|
||||
|
||||
//StartPeeringMgr will start the peering RPCs
|
||||
func StartPeeringMgr(ctx context.Context, log *relaylogger.RelayLog, exitChan chan<- bool, config *ServerConfig) {
|
||||
var tlsConfig *tls.Config
|
||||
var err error
|
||||
var peerSeviceHost string
|
||||
|
||||
peerlog = log.WithName("PeeringMgr")
|
||||
|
||||
if utils.PeerCache == nil {
|
||||
peerlog.Error(
|
||||
nil,
|
||||
"peer client cache is nil",
|
||||
)
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
//Peer Service Clint certs is popultaed from boot strap use it
|
||||
if len(utils.PeerCertificate) > 0 && len(utils.PeerPrivateKey) > 0 && len(utils.PeerCACertificate) > 0 {
|
||||
u, err := url.Parse(utils.PeerServiceURI)
|
||||
if err != nil {
|
||||
peerlog.Error(
|
||||
nil,
|
||||
"peer servic uri parse failed",
|
||||
)
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
//Load certificates
|
||||
tlsConfig, err = ClientTLSConfigFromBytes(utils.PeerCertificate, utils.PeerPrivateKey, utils.PeerCACertificate, u.Host)
|
||||
peerSeviceHost = u.Host
|
||||
} else {
|
||||
//Load certificates
|
||||
tlsConfig, err = ClientTLSConfig(config.Controller.ClientCRT, config.Controller.ClientKEY, config.Controller.RootCA, config.Controller.PeerProbeSNI)
|
||||
peerSeviceHost = config.Controller.PeerProbeSNI
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
peerlog.Error(
|
||||
err,
|
||||
"Error loading peer TLC config",
|
||||
)
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
|
||||
//enforce TLS mutual authN
|
||||
transportCreds := credentials.NewTLS(tlsConfig)
|
||||
|
||||
connectRetry:
|
||||
log.Debug("Start Peer grpc dial")
|
||||
conn, err := comgrpc.NewSecureClientConn(ctx, peerSeviceHost, transportCreds)
|
||||
if err != nil {
|
||||
peerlog.Error(
|
||||
err,
|
||||
"failed to connect to peer server, retry in 10 seconds",
|
||||
peerSeviceHost,
|
||||
)
|
||||
time.Sleep(10 * time.Second)
|
||||
goto connectRetry
|
||||
}
|
||||
|
||||
log.Info("grpc connected to peer service", peerSeviceHost)
|
||||
client := relayrpc.NewRelayPeerServiceClient(conn)
|
||||
|
||||
// create RPC streams
|
||||
helloStream, err := client.RelayPeerHelloRPC(context.Background())
|
||||
if err != nil {
|
||||
peerlog.Error(
|
||||
err,
|
||||
"failed to create HelloRPC stream with peer server, retry in 10 seconds",
|
||||
peerSeviceHost,
|
||||
)
|
||||
conn.Close()
|
||||
time.Sleep(10 * time.Second)
|
||||
goto connectRetry
|
||||
}
|
||||
|
||||
probeStream, err := client.RelayPeerProbeRPC(context.Background())
|
||||
if err != nil {
|
||||
peerlog.Error(
|
||||
err,
|
||||
"failed to create ProbeRPC stream with peer server, retry in 10 seconds",
|
||||
peerSeviceHost,
|
||||
)
|
||||
conn.Close()
|
||||
time.Sleep(10 * time.Second)
|
||||
goto connectRetry
|
||||
}
|
||||
|
||||
surveyStream, err := client.RelayPeerSurveyRPC(context.Background())
|
||||
if err != nil {
|
||||
peerlog.Error(
|
||||
err,
|
||||
"failed to create SurveyRPC stream with peer server, retry in 10 seconds",
|
||||
peerSeviceHost,
|
||||
)
|
||||
conn.Close()
|
||||
time.Sleep(10 * time.Second)
|
||||
goto connectRetry
|
||||
}
|
||||
|
||||
peerlog.Debug(
|
||||
"created RPC streams with peer server",
|
||||
peerSeviceHost,
|
||||
)
|
||||
|
||||
rpcctx, rpccancel := context.WithCancel(context.Background())
|
||||
go peerclient.ClientHelloRPC(rpcctx, helloStream, utils.PeerHelloInterval, utils.RelayUUID, utils.GetRelayIP)
|
||||
//Add a init time wait for hello stream to finish
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
go peerclient.ClientProbeRPC(rpcctx, probeStream, utils.PeerCache, utils.RelayUUID, utils.PeerCacheDefaultExpiry, PeerProbeChanel, utils.GetRelayIPPort)
|
||||
|
||||
go peerclient.ClientSurveyRPC(rpcctx, surveyStream, utils.RelayUUID, utils.GetRelayIPPort, dialinCountLookup)
|
||||
|
||||
for {
|
||||
//Watch for errors in rpc streams.
|
||||
//On error cancel the streams and reconnect.
|
||||
//HelloRPC send heartbeats in every 60Sec.
|
||||
//If there is underlying connectivity issues
|
||||
//HelloRPC will detect it with in 60Sec,
|
||||
select {
|
||||
case <-helloStream.Context().Done():
|
||||
rpccancel()
|
||||
conn.Close()
|
||||
time.Sleep(5 * time.Second)
|
||||
goto connectRetry
|
||||
case <-probeStream.Context().Done():
|
||||
rpccancel()
|
||||
conn.Close()
|
||||
time.Sleep(5 * time.Second)
|
||||
goto connectRetry
|
||||
case <-surveyStream.Context().Done():
|
||||
rpccancel()
|
||||
conn.Close()
|
||||
time.Sleep(5 * time.Second)
|
||||
goto connectRetry
|
||||
case <-ctx.Done():
|
||||
rpccancel()
|
||||
slog.Error(
|
||||
ctx.Err(),
|
||||
"Stopping PeeringMgr",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
package tunnel
|
||||
|
||||
// Dialin defines a dialin.
|
||||
type Dialin struct {
|
||||
Protocol string
|
||||
Addr string
|
||||
ServerName string
|
||||
RootCA []byte
|
||||
ServerCRT []byte
|
||||
ServerKEY []byte
|
||||
Version string
|
||||
}
|
||||
|
||||
// Relay defines a relay.
|
||||
type Relay struct {
|
||||
Protocol string
|
||||
Addr string
|
||||
DialinSfx string
|
||||
ServerName string
|
||||
RootCA []byte
|
||||
ServerCRT []byte
|
||||
ServerKEY []byte
|
||||
Version string
|
||||
}
|
||||
|
||||
// ControllerInfo defines controller info.
|
||||
type ControllerInfo struct {
|
||||
Addr string
|
||||
PeerProbeSNI string
|
||||
RootCA string
|
||||
ClientCRT string
|
||||
ClientKEY string
|
||||
}
|
||||
|
||||
// ServerConfig is the configuration for relay server
|
||||
type ServerConfig struct {
|
||||
RelayAddr string
|
||||
Relays map[string]*Relay
|
||||
CDRelays map[string]*Relay
|
||||
Dialins map[string]*Dialin
|
||||
Controller ControllerInfo
|
||||
AuditPath string
|
||||
}
|
||||
@@ -0,0 +1,713 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/relay/pkg/relaylogger"
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"github.com/felixge/tcpkeepalive"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Known relay services
|
||||
const (
|
||||
KUBECTL = "kubectl"
|
||||
KUBEWEB = "kubeweb"
|
||||
GENTCP = "tcp"
|
||||
HTTPUP = "httpupgrade"
|
||||
)
|
||||
|
||||
// Known server types
|
||||
const (
|
||||
RELAY = "relay"
|
||||
CDRELAY = "cdrelay"
|
||||
RELAYAGENT = "relay-agent"
|
||||
CDRELAYAGENT = "cdrelay-agent"
|
||||
DIALIN = "dialin"
|
||||
JoinString = "--"
|
||||
)
|
||||
|
||||
// Relay Network Types
|
||||
const (
|
||||
KUBECTLCORE = "rafay-core-relay-agent"
|
||||
KUBECTLDEDICATED = "rafay-non-core-relay-agent"
|
||||
CDAGENTCORE = "rafay-core-cd-relay-agent"
|
||||
)
|
||||
|
||||
//SNICertificate sni based certs
|
||||
type SNICertificate struct {
|
||||
CertFile []byte
|
||||
KeyFile []byte
|
||||
}
|
||||
|
||||
//Relaynetwork configmap data
|
||||
type Relaynetwork struct {
|
||||
Token string `json:"token"` // bootstrap agent token
|
||||
Addr string `json:"addr"` // bootstrap register host
|
||||
Domain string `json:"endpoint"` // dialout domain
|
||||
Name string `json:"name"` // network name
|
||||
TemplateToken string `json:"templateToken"` // bootstrap template token
|
||||
Upstream string `json:"upstream"` // upstream tcp service host:port
|
||||
}
|
||||
|
||||
//RelayNetworkConfig config for relay agent
|
||||
type RelayNetworkConfig struct {
|
||||
// Network configmap
|
||||
Network Relaynetwork
|
||||
// RelayAgentCert used for relay-agent client cert
|
||||
RelayAgentCert []byte
|
||||
// RelayAgentKey used for relay-agent client cert
|
||||
RelayAgentKey []byte
|
||||
// RelayAgentCACert used for relay-agent client cert
|
||||
RelayAgentCACert []byte
|
||||
}
|
||||
|
||||
// Known protocol types.
|
||||
const (
|
||||
HTTP = "HTTP"
|
||||
HTTPS = "https"
|
||||
TCP = "tcp"
|
||||
UNIX = "unix"
|
||||
)
|
||||
|
||||
// Known dialin types
|
||||
const (
|
||||
KUBECTLDILAIN = "kubectldialin"
|
||||
KUBEWEBDIALIN = "kubewebdialin"
|
||||
PEERKEY = "04112005676520746869732070617373776f726420746f206120736563726574"
|
||||
)
|
||||
|
||||
const (
|
||||
//HeaderError ..
|
||||
HeaderError = "X-Error"
|
||||
//HeaderAction ...
|
||||
HeaderAction = "X-Action"
|
||||
//HeaderForwardedHost ..
|
||||
HeaderForwardedHost = "X-Forwarded-Host"
|
||||
//HeaderForwardedService ..
|
||||
HeaderForwardedService = "X-Forwarded-Service"
|
||||
|
||||
//HeaderRafayUserName ..
|
||||
HeaderRafayUserName = "X-Rafay-User"
|
||||
//HeaderRafayNamespace ..
|
||||
HeaderRafayNamespace = "X-Rafay-Namespace"
|
||||
//HeaderRafayScope ..
|
||||
HeaderRafayScope = "X-Rafay-Scope"
|
||||
//HeaderRafayAllow ..
|
||||
HeaderRafayAllow = "X-Rafay-Allow"
|
||||
//HeaderRafayAuthZSA yaml contains service account
|
||||
HeaderRafayAuthZSA = "X-Rafay-AuthzSA"
|
||||
//HeaderRafayAuthZRole yaml contains role
|
||||
HeaderRafayAuthZRole = "X-Rafay-AuthzRole"
|
||||
//HeaderRafayAuthZRoleBinding yaml contains rolebinding
|
||||
HeaderRafayAuthZRoleBinding = "X-Rafay-AuthzRoleBinding"
|
||||
//HeaderRafayServiceAccountNoExpire don't expire service account
|
||||
HeaderRafayServiceAccountNoExpire = "X-Rafay-ServiceAccount-NoExpire"
|
||||
//HeaderClearSecret to clear the current secret cache of user
|
||||
HeaderClearSecret = "X-Rafay-Clear-Cache"
|
||||
)
|
||||
|
||||
// Known actions.
|
||||
const (
|
||||
ActionProxy = "proxy"
|
||||
|
||||
// DefaultAuditPolicyPath default audit policy filter path
|
||||
// k8s audit need a file path
|
||||
DefaultAuditPolicyPath = "./relayaudit.yaml"
|
||||
|
||||
//DefaultAuditPath defailt audit log files path
|
||||
DefaultAuditPath = "-" // - means standard out
|
||||
|
||||
//RafayRelayServiceAccountNameSpace namespace used to create service account for relays
|
||||
RafayRelayServiceAccountNameSpace = "system-sa"
|
||||
)
|
||||
|
||||
var (
|
||||
// LogLevel loglevel set from commadline
|
||||
LogLevel int
|
||||
// Mode relay/relay-agent
|
||||
Mode string
|
||||
// ClusterID unique id of the cluster
|
||||
ClusterID string
|
||||
// AgentID unique id for cd agent
|
||||
AgentID string
|
||||
// ExitChan trigger this channel to exit
|
||||
ExitChan = make(chan bool)
|
||||
// TerminateChan trigger this channel to exit
|
||||
TerminateChan = make(chan bool)
|
||||
// IdleTimeout is the maximum amount of time to wait for the
|
||||
// next read/write before closing connection.
|
||||
IdleTimeout = 5 * time.Minute
|
||||
// DefaultTimeout specifies a general purpose timeout.
|
||||
DefaultTimeout = 5 * time.Minute
|
||||
// DefaultPingTimeout specifies a ping timeout.
|
||||
DefaultPingTimeout = 5 * time.Second
|
||||
|
||||
// DefaultKeepAliveIdleTime specifies how long connection can be idle
|
||||
// before sending keepalive message.
|
||||
DefaultKeepAliveIdleTime = 15 * time.Second
|
||||
|
||||
// DefaultKeepAliveCount specifies maximal number of keepalive messages
|
||||
// sent before marking connection as dead.
|
||||
DefaultKeepAliveCount = 3
|
||||
|
||||
// DefaultKeepAliveInterval specifies how often retry sending keepalive
|
||||
// messages when no response is received.
|
||||
DefaultKeepAliveInterval = 5 * time.Second
|
||||
|
||||
//DefaultMuxTimeout specifies vmux timeout
|
||||
DefaultMuxTimeout = 10 * time.Second
|
||||
|
||||
//UNIXSOCKET prefix path for unix socket
|
||||
UNIXSOCKET = "/tmp/relay-unix-" // need to change this from tmp to appropriate path after integration
|
||||
|
||||
//UNIXAGENTSOCKET prefix path for unix socket
|
||||
UNIXAGENTSOCKET = "/tmp/relay-agent-unix-" // need to change this from tmp to appropriate path after integration
|
||||
|
||||
//ProxyProtocolSize Default PROXY PROTO buffer size
|
||||
ProxyProtocolSize = 1024
|
||||
|
||||
//RelayUUID runtime Unique ID for relay
|
||||
RelayUUID string
|
||||
|
||||
//RelayIPFromConfig IP address of the relay for peering
|
||||
RelayIPFromConfig string
|
||||
|
||||
//PeerCache stores peer dialin info
|
||||
PeerCache *ristretto.Cache
|
||||
|
||||
//ServiceAccountCache stores service account, role, role binding in relay-agetn in connector
|
||||
ServiceAccountCache *ristretto.Cache
|
||||
|
||||
//ServiceAccountCacheDefaultExpiry default expiry
|
||||
ServiceAccountCacheDefaultExpiry = 600 * time.Second
|
||||
|
||||
//PeerCacheDefaultExpiry default expiry
|
||||
PeerCacheDefaultExpiry = 600 * time.Second
|
||||
//PeerHelloInterval heartbeat interval
|
||||
PeerHelloInterval = 60 * time.Second
|
||||
//PeerServiceURI is the URI to join peering service
|
||||
PeerServiceURI string
|
||||
//PeerCertificate used for peering service communication
|
||||
PeerCertificate []byte
|
||||
//PeerPrivateKey used for peering service communication
|
||||
PeerPrivateKey []byte
|
||||
//PeerCACertificate used for peering service communication
|
||||
PeerCACertificate []byte
|
||||
|
||||
//RelayUserCert used for user/peer communication
|
||||
RelayUserCert []byte
|
||||
//RelayUserKey used for user/peer communication
|
||||
RelayUserKey []byte
|
||||
//RelayUserCACert used for user/peer communication
|
||||
RelayUserCACert []byte
|
||||
|
||||
//RelayUserPort user facing seerver port
|
||||
RelayUserPort int
|
||||
// RelayUserHost user facing seerver host (domain)
|
||||
RelayUserHost string
|
||||
//RelayConnectorCert used for relay-connector termination
|
||||
RelayConnectorCert []byte
|
||||
//RelayConnectorKey used for relay-connector termination
|
||||
RelayConnectorKey []byte
|
||||
//RelayConnectorCACert used for relay-connector termination
|
||||
RelayConnectorCACert []byte
|
||||
// RelayConnectorHost connector facing server host (domain)
|
||||
RelayConnectorHost string
|
||||
// RelayConnectorPort connector facing server port
|
||||
RelayConnectorPort int
|
||||
|
||||
// CDRelayUserCert used for client/peer communication
|
||||
CDRelayUserCert []byte
|
||||
// CDRelayUserKey used for client/peer communication
|
||||
CDRelayUserKey []byte
|
||||
// CDRelayUserCACert used for client/peer communication
|
||||
CDRelayUserCACert []byte
|
||||
// CDRelayUserHost client facing server host
|
||||
CDRelayUserHost string
|
||||
// CDRelayUserPort client facing server port
|
||||
CDRelayUserPort int
|
||||
// CDRelayConnectorCert used for cd-relay-connector termination
|
||||
CDRelayConnectorCert []byte
|
||||
// CDRelayConnectorKey used for cd-relay-connector termination
|
||||
CDRelayConnectorKey []byte
|
||||
// CDRelayConnectorCACert used for cd-relay-connector termination
|
||||
CDRelayConnectorCACert []byte
|
||||
// CDRelayConnectorHost connector facing server host (domain)
|
||||
CDRelayConnectorHost string
|
||||
// CDRelayConnectorPort connector facing server port
|
||||
CDRelayConnectorPort int
|
||||
|
||||
//RelayNetworks list of relaynemtworks from configmap
|
||||
RelayNetworks []Relaynetwork
|
||||
// RelayAgentConfig map of relay agent configurations
|
||||
RelayAgentConfig map[string]RelayNetworkConfig
|
||||
|
||||
// MaxDials max connections dialed
|
||||
MaxDials = 10
|
||||
|
||||
// MinDials minimum connections dialed
|
||||
MinDials = 8
|
||||
|
||||
//PODNAME name of the pod
|
||||
PODNAME string
|
||||
|
||||
// DialoutProxy setting used while connecting to relay IP:PORT or HOST:PORT format
|
||||
DialoutProxy = ""
|
||||
|
||||
// DialoutProxyAuth Proxy-Authorization header base64 encoded value of user:password
|
||||
DialoutProxyAuth = ""
|
||||
|
||||
// DefaultTCPUpstream default TCP upstream
|
||||
DefaultTCPUpstream = "127.0.0.1:16001"
|
||||
|
||||
// ScalingStreamsThreshold concurrent streams count to trigger scaling
|
||||
ScalingStreamsThreshold = 400
|
||||
|
||||
// ScalingStreamsRateThreshold new streams rate to trigger scaling
|
||||
ScalingStreamsRateThreshold = 200
|
||||
|
||||
// MaxScaleMultiplier multiplier to limit max scaled connections
|
||||
MaxScaleMultiplier = 3
|
||||
|
||||
// HealingInterval time to close idle scaled connection
|
||||
HealingInterval = 24 // Hour
|
||||
)
|
||||
|
||||
//CountWriter to measure bytes
|
||||
type CountWriter struct {
|
||||
W io.Writer
|
||||
Count int64
|
||||
}
|
||||
|
||||
// ControlMessage is sent from server to client before streaming data. It's
|
||||
// used to inform client about the data and action to take. Based on that client
|
||||
// routes requests to backend services.
|
||||
type ControlMessage struct {
|
||||
Action string
|
||||
ForwardedHost string
|
||||
ForwardedService string
|
||||
RemoteAddr string
|
||||
RafayUserName string
|
||||
RafayNamespace string
|
||||
RafayScope string
|
||||
RafayAllow string
|
||||
RafayAuthz string
|
||||
}
|
||||
|
||||
// ProxyConfig configs for the proxy
|
||||
type ProxyConfig struct {
|
||||
Protocol string
|
||||
Addr string
|
||||
ServiceSNI string
|
||||
RootCA string
|
||||
ClientCRT string
|
||||
ClientKEY string
|
||||
Upstream string
|
||||
UpstreamClientCRT string
|
||||
UpstreamClientKEY string
|
||||
UpstreamRootCA string
|
||||
UpstreamSkipVerify bool
|
||||
UpstreamKubeConfig string
|
||||
Version string
|
||||
}
|
||||
|
||||
//ProxyProtocolMessage used across dialin unix socket
|
||||
type ProxyProtocolMessage struct {
|
||||
DialinKey string
|
||||
UserName string
|
||||
SNI string
|
||||
}
|
||||
|
||||
type ServiceAccountCacheObject struct {
|
||||
RafayAuthzSA string
|
||||
RafayAuthzRole string
|
||||
RafayAuthzRoleBind string
|
||||
Md5sum string
|
||||
Key string
|
||||
}
|
||||
|
||||
//OnEvict cache on eviction call back function
|
||||
type OnEvict = func(item *ristretto.Item)
|
||||
|
||||
//Fatal to exit the program
|
||||
func Fatal(format string, a ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, format, a...)
|
||||
fmt.Fprint(os.Stderr, "\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
//CloneHeader clone http headers
|
||||
func CloneHeader(h http.Header) http.Header {
|
||||
h2 := make(http.Header, len(h))
|
||||
for k, vv := range h {
|
||||
vv2 := make([]string, len(vv))
|
||||
copy(vv2, vv)
|
||||
h2[k] = vv2
|
||||
}
|
||||
return h2
|
||||
}
|
||||
|
||||
//SetXForwardedFor ...
|
||||
func SetXForwardedFor(h http.Header, remoteAddr string) {
|
||||
clientIP, _, err := net.SplitHostPort(remoteAddr)
|
||||
if err == nil {
|
||||
// If we aren't the first proxy retain prior
|
||||
// X-Forwarded-For information as a comma+space
|
||||
// separated list and fold multiple headers into one.
|
||||
if prior, ok := h["X-Forwarded-For"]; ok {
|
||||
clientIP = strings.Join(prior, ", ") + ", " + clientIP
|
||||
}
|
||||
h.Set("X-Forwarded-For", clientIP)
|
||||
}
|
||||
}
|
||||
|
||||
//SetXRAYUUID ...
|
||||
func SetXRAYUUID(h http.Header) {
|
||||
var reluuid string
|
||||
|
||||
reluuid = RelayUUID
|
||||
// If this isn't the first relay retain prior
|
||||
// UUIDs information as a comma+space
|
||||
// separated list and fold multiple headers into one.
|
||||
if prior, ok := h["X-Rafay-XRAY-RELAYUUID"]; ok {
|
||||
reluuid = strings.Join(prior, ", ") + ", " + reluuid
|
||||
}
|
||||
h.Set("X-Rafay-XRAY-RELAYUUID", reluuid)
|
||||
}
|
||||
|
||||
//SetXForwardedRafay set rafay headers
|
||||
func SetXForwardedRafay(h http.Header, msg *ControlMessage) {
|
||||
h.Set("X-Rafay-User", msg.RafayUserName)
|
||||
h.Set("X-Rafay-Namespace", msg.RafayNamespace)
|
||||
h.Set("X-Rafay-Scope", msg.RafayScope)
|
||||
h.Set("X-Rafay-Allow", msg.RafayAllow)
|
||||
}
|
||||
|
||||
//UnSetXForwardedRafay set rafay headers
|
||||
func UnSetXForwardedRafay(h http.Header) {
|
||||
h.Del("X-Rafay-Scope")
|
||||
h.Del("X-Rafay-Allow")
|
||||
h.Del("X-Forwarded-For")
|
||||
h.Del("X-Rafay-XRAY-RELAYUUID")
|
||||
h.Del("X-Rafay-Audit")
|
||||
h.Del("X-Rafay-Cluster-Id")
|
||||
h.Del("X-Rafay-Cluster-Servername")
|
||||
h.Del("X-Rafay-Peer-Hash")
|
||||
h.Del("X-Rafay-Peer-Nonce")
|
||||
h.Del("X-Rafay-Sessionkey")
|
||||
h.Del("X-Rafay-User-Cert-Issued")
|
||||
}
|
||||
|
||||
//Transfer transfer by io.Copy
|
||||
func Transfer(dst io.Writer, src io.Reader, tlog *relaylogger.RelayLog, direction string) {
|
||||
n, err := io.Copy(dst, src)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "context canceled") && !strings.Contains(err.Error(), "CANCEL") && !strings.Contains(err.Error(), "i/o timeout") && !strings.Contains(err.Error(), "closed network") {
|
||||
tlog.Error(
|
||||
err,
|
||||
"io.Copy error",
|
||||
"direction", direction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
tlog.Debug(
|
||||
"action transferred",
|
||||
"bytes", n,
|
||||
"in direction", direction,
|
||||
)
|
||||
}
|
||||
|
||||
// WriteToHeader writes ControlMessage to HTTP header.
|
||||
func WriteToHeader(h http.Header, c *ControlMessage) {
|
||||
h.Set(HeaderAction, string(c.Action))
|
||||
h.Set(HeaderForwardedHost, c.ForwardedHost)
|
||||
h.Set(HeaderForwardedService, c.ForwardedService)
|
||||
h.Set(HeaderRafayUserName, c.RafayUserName)
|
||||
h.Set(HeaderRafayNamespace, c.RafayNamespace)
|
||||
h.Set(HeaderRafayScope, c.RafayScope)
|
||||
h.Set(HeaderRafayAllow, c.RafayAllow)
|
||||
}
|
||||
|
||||
func (cw *CountWriter) Write(p []byte) (n int, err error) {
|
||||
n, err = cw.W.Write(p)
|
||||
cw.Count += int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
//CopyHeader copy header
|
||||
func CopyHeader(dst, src http.Header) {
|
||||
for k, v := range src {
|
||||
vv := make([]string, len(v))
|
||||
copy(vv, v)
|
||||
dst[k] = vv
|
||||
}
|
||||
}
|
||||
|
||||
// ReadControlMessage reads ControlMessage from HTTP headers.
|
||||
func ReadControlMessage(r *http.Request) (*ControlMessage, error) {
|
||||
msg := ControlMessage{
|
||||
Action: r.Header.Get(HeaderAction),
|
||||
ForwardedHost: r.Header.Get(HeaderForwardedHost),
|
||||
ForwardedService: r.Header.Get(HeaderForwardedService),
|
||||
RafayUserName: r.Header.Get(HeaderRafayUserName),
|
||||
RafayNamespace: r.Header.Get(HeaderRafayNamespace),
|
||||
RafayScope: r.Header.Get(HeaderRafayScope),
|
||||
RafayAllow: r.Header.Get(HeaderRafayAllow),
|
||||
RemoteAddr: r.RemoteAddr,
|
||||
}
|
||||
|
||||
var missing []string
|
||||
|
||||
if msg.Action == "" {
|
||||
missing = append(missing, HeaderAction)
|
||||
}
|
||||
if msg.ForwardedHost == "" {
|
||||
missing = append(missing, HeaderForwardedHost)
|
||||
}
|
||||
if msg.ForwardedService == "" {
|
||||
missing = append(missing, HeaderForwardedService)
|
||||
}
|
||||
|
||||
if len(missing) != 0 {
|
||||
return nil, fmt.Errorf("missing headers: %s", missing)
|
||||
}
|
||||
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
//FlushWriter flush writer
|
||||
type FlushWriter struct {
|
||||
W io.Writer
|
||||
}
|
||||
|
||||
func (fw FlushWriter) Write(p []byte) (n int, err error) {
|
||||
n, err = fw.W.Write(p)
|
||||
if f, ok := fw.W.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//KeepAlive set keepalive
|
||||
func KeepAlive(conn net.Conn) error {
|
||||
return tcpkeepalive.SetKeepAlive(conn, DefaultKeepAliveIdleTime, DefaultKeepAliveCount, DefaultKeepAliveInterval)
|
||||
}
|
||||
|
||||
//GenUUID generates a google UUID
|
||||
func GenUUID() {
|
||||
id := uuid.New()
|
||||
RelayUUID = id.String()
|
||||
}
|
||||
|
||||
//GetRelayIP get relay IP address
|
||||
func GetRelayIP() string {
|
||||
if RelayIPFromConfig == "" {
|
||||
name, err := os.Hostname()
|
||||
if err == nil {
|
||||
addr, err := net.LookupIP(name)
|
||||
if err == nil {
|
||||
return addr[0].String()
|
||||
}
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return RelayIPFromConfig
|
||||
}
|
||||
|
||||
// GetRelayIPPort get relay IP:PORT of user facing server
|
||||
func GetRelayIPPort() string {
|
||||
if RelayIPFromConfig == "" {
|
||||
return GetRelayIP() + ":" + strconv.Itoa(RelayUserPort)
|
||||
}
|
||||
return RelayIPFromConfig
|
||||
}
|
||||
|
||||
//CheckRelayLoops :does XRAY UUDI already present in header?
|
||||
func CheckRelayLoops(h http.Header) bool {
|
||||
if uuidHdr, ok := h["X-Rafay-XRAY-RELAYUUID"]; ok {
|
||||
allIds := strings.Join(uuidHdr, ", ")
|
||||
matched, err := regexp.Match(RelayUUID, []byte(allIds))
|
||||
if err == nil && matched {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InitCache initialize the cache to store dialin cluster-connection
|
||||
// information of peers. When a dialin miss happens look into this cache
|
||||
// to find the peer IP address to forward the user connection.
|
||||
func InitCache(evict OnEvict) (*ristretto.Cache, error) {
|
||||
return ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1e7, // Num keys to track frequency of (10M).
|
||||
MaxCost: 1 << 30, // Maximum cost of cache (1GB).
|
||||
BufferItems: 64, // Number of keys per Get buffer.
|
||||
OnEvict: evict,
|
||||
})
|
||||
}
|
||||
|
||||
// InsertCache inserts the value to cache
|
||||
func InsertCache(cache *ristretto.Cache, expiry time.Duration, key, value interface{}) bool {
|
||||
return cache.SetWithTTL(key, value, 100, expiry)
|
||||
}
|
||||
|
||||
// GetCache get value from cache
|
||||
func GetCache(cache *ristretto.Cache, key interface{}) (interface{}, bool) {
|
||||
return cache.Get(key)
|
||||
|
||||
}
|
||||
|
||||
// DeleteCache delete value from cache
|
||||
func DeleteCache(cache *ristretto.Cache, key interface{}) {
|
||||
cache.Del(key)
|
||||
}
|
||||
|
||||
//WriteFile overwrite if exist
|
||||
func WriteFile(filename, data string) error {
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
file.WriteString(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
// validOptionalPort reports whether port is either an empty string
|
||||
// or matches /^:\d*$/
|
||||
func validOptionalPort(port string) bool {
|
||||
if port == "" {
|
||||
return true
|
||||
}
|
||||
if port[0] != ':' {
|
||||
return false
|
||||
}
|
||||
for _, b := range port[1:] {
|
||||
if b < '0' || b > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// SplitHostPort separates host and port. If the port is not valid, it returns
|
||||
// the entire input as host, and it doesn't check the validity of the host.
|
||||
func SplitHostPort(hostport string) (host, port string) {
|
||||
host = hostport
|
||||
|
||||
colon := strings.LastIndexByte(host, ':')
|
||||
if colon != -1 && validOptionalPort(host[colon:]) {
|
||||
host, port = host[:colon], host[colon+1:]
|
||||
}
|
||||
|
||||
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
|
||||
host = host[1 : len(host)-1]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IsHTTPS returns true if port is 443
|
||||
func IsHTTPS(addr string) bool {
|
||||
_, port, err := net.SplitHostPort(addr)
|
||||
if err == nil {
|
||||
if port == "443" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// PeerSetHeaderNonce header
|
||||
func PeerSetHeaderNonce(h http.Header) error {
|
||||
key, _ := hex.DecodeString(PEERKEY)
|
||||
|
||||
data := h.Get("X-Rafay-XRAY-RELAYUUID")
|
||||
if data == "" {
|
||||
return fmt.Errorf("no X-Rafay-XRAY-RELAYUUID header")
|
||||
}
|
||||
value := []byte(data)
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nonce := make([]byte, 12)
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
aesgcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ciphertext := aesgcm.Seal(nil, nonce, value, nil)
|
||||
hash := hex.EncodeToString(ciphertext)
|
||||
|
||||
peerNonce := hex.EncodeToString(nonce)
|
||||
h.Set("X-Rafay-Peer-Nonce", peerNonce)
|
||||
h.Set("X-Rafay-Peer-Hash", hash)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckPeerHeaders validates upstreams request
|
||||
func CheckPeerHeaders(h http.Header) bool {
|
||||
key, _ := hex.DecodeString(PEERKEY)
|
||||
|
||||
hash := h.Get("X-Rafay-Peer-Hash")
|
||||
if hash == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
peerNonce := h.Get("X-Rafay-Peer-Nonce")
|
||||
if peerNonce == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
expected := h.Get("X-Rafay-XRAY-RELAYUUID")
|
||||
if expected == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
ciphertext, _ := hex.DecodeString(hash)
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
aesgcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
nonce, _ := hex.DecodeString(peerNonce)
|
||||
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if string(plaintext) == expected {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
# rafay-relay unit testing
|
||||
k8s api server relay unit testing
|
||||
|
||||
|
||||
## Environment
|
||||
Please refer below image to setup your test environtment. You can run server and client in the same system.
|
||||
|
||||

|
||||
|
||||
|
||||
## Testing
|
||||
Add entries in /etc/host or in your DNS-server for the relay-server ipaddress.\
|
||||
The User facing DNS is **cluster1.kubectl.relay.rafay.dev**\
|
||||
The Dialin facing DNS is **cluster1.kubectldialin.relay.rafay.dev**\
|
||||
For example; to run client and server in local system, the /etc/host will have entries like below.
|
||||
```
|
||||
127.0.0.1 cluster1.kubectl.relay.rafay.dev
|
||||
127.0.0.1 cluster1.kubectldialin.relay.rafay.dev
|
||||
```
|
||||
|
||||
### Client System setup
|
||||
Makesure $KUBECONFIG environment variable is set in the client system\
|
||||
(OR)
|
||||
You can use testdata/kubectlconfigs/kubeconfig and customise it for your setup.
|
||||
```
|
||||
export KUBECONFIG=testdata/kubectlconfigs/kubeconfig
|
||||
```
|
||||
|
||||
### Cluster serviceaccount setup
|
||||
Apply config pkg/proxy/testdata/role.yaml
|
||||
```
|
||||
kubectl apply -f pkg/proxy/testdata/role.yaml
|
||||
```
|
||||
|
||||
Run service using below commands
|
||||
```
|
||||
sudo relay.exe -config ./testdata/server.yaml start server
|
||||
```
|
||||
### Relay client for cluster1
|
||||
```
|
||||
relay.exe -config ./testdata/client-cluster1.yaml start client
|
||||
|
||||
```
|
||||
### Relay client for cluster2
|
||||
```
|
||||
relay.exe -config ./testdata/client-cluster2.yaml start client
|
||||
|
||||
```
|
||||
|
||||
### Using Relay for kubectl
|
||||
In kubeconfig set server address to relay.\
|
||||
Relay uses MTLS to authenticate. Set `client-certificate` and `client-key` to cert signed by the relay service rootCA. For kubectl to validate the relay server set `certificate-authority`. Use `--insecure-skip-tls-verify` to skip the server validation.
|
||||
|
||||
Examples:
|
||||
```
|
||||
kubectl --kubeconfig testdata/kubectlconfigs/kubeconfigproxy-cluster1 get pods
|
||||
kubectl --kubeconfig testdata/kubectlconfigs/kubeconfigproxy-cluster2 get pods
|
||||
kubectl --kubeconfig testdata/kubectlconfigs/kubeconfigproxy-cluster1 exec -it demo-sa1 -- /bin/sh
|
||||
kubectl --kubeconfig testdata/kubectlconfigs/kubeconfigproxy-cluster2 exec -it demo-sa1 -- /bin/sh
|
||||
```
|
||||
|
||||
### Production
|
||||
Relay server need following environment variables
|
||||
|
||||
POD_NAME - name of the relay instaance (auto generated)
|
||||
POD_NAMESPACE - namespace of the relay instance
|
||||
|
||||
RAFAY_SENTRY - URL to boostrap with sentry service
|
||||
RAFAY_RELAY_PEERSERVICE - To join gRPC with sentry peer service
|
||||
|
||||
|
||||
RELAY_USER_DOMAIN - domain suffix for relay user facing server
|
||||
RELAY_CONNECTOR_DOMAIN - domain suffix for relay connector facing domain
|
||||
|
||||
RELAY_TOKEN - Peer Service Token bootstrapping
|
||||
RELAY_USER_TOKEN - Relay user facing server bootstrapping
|
||||
RELAY_CONNECTOR_TOKEN - Relay connector facing server bootstrapping
|
||||
|
||||
Examples:
|
||||
```
|
||||
export RAFAY_SENTRY=http://sentry.rafay.dev:9000
|
||||
export RAFAY_RELAY_PEERSERVICE=http://peering.sentry.rafay.local:7001
|
||||
|
||||
export RELAY_USER_DOMAIN="user.relay.rafay.local"
|
||||
export RELAY_CONNECTOR_DOMAIN="core-connector.relay.rafay.local"
|
||||
|
||||
export RELAY_TOKEN=bqfvhabipt3a2g46986g
|
||||
export RELAY_USER_TOKEN=bqfvhabipt3a2g46987g
|
||||
export RELAY_CONNECTOR_TOKEN=bqfvhabipt3a2g469870
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEWjCCAkICCQD0kF4yo85tQzANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDEwOTE5MTUx
|
||||
NVoXDTMwMDEwNjE5MTUxNVowgYAxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTET
|
||||
MBEGA1UEBwwKUGxlYXNhbnRvbjEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0Rl
|
||||
djExMC8GA1UEAwwocmVsYXlzZXJ2ZXIxLUFCQ0QtMTIzNDU2LnJlbGF5LnJhZmF5
|
||||
LmRldjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN51AZQAYIoAAQUk
|
||||
G7qFudNDMT03FO6j+ThIsqQzqXgHOCBDVMhaWs4qKJzMD+8vtnPHzz2t0ksYsnKj
|
||||
YfO21C/kzbMz3yBZSyFA/eqEA/CLbyzECs+eaNHX7hDaVcHX22Rbi+W7zmjJE2LZ
|
||||
5oxGoQKnSQFEn/0SsjKX4DdF+Rlw4TBgBuJ77tXnslZr+Hcgrt8dOApuWZ6v5PPN
|
||||
aM72L1Gp1eP7ViUia8yc4AO2UjdO8iGSaDjy/mlWVLsK9Lb+/O5RGMmqcN+o6Mnd
|
||||
U6WMOtVgkjfNeIZWJ0RdmEkR/JMyOmZauyqZiW7stOVhtOxfhE5b2N7VbqtT989q
|
||||
OPZ/x38CAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAng07c+Kn65mvGawiV3ZICuTy
|
||||
cpfnlPEmpx4ZtDUsTIyRgaRkPpmPFkJee8kNPIrY68EeLmQB6oA976cx6+N9B61U
|
||||
2oBG1HpbdtTOwvj9qid3B+syzDJXmgpEWczsNAptDqOfa/4jGzp53rORfljXnqBx
|
||||
DwJhe5XI6ZJ0DLK1piNneq076qElylPgCV//tzyNn9mjaNCl64FjJyhER36UWEm7
|
||||
o4JCQkprppyocWs/NKq6ENsNsNPdWH+ZxiVy2eIGOGMk6zWu8VcCGaRDQDumkQT3
|
||||
yMh4DBfyCfbd8liOYLsLuYkGaz0Ew76TgMr875v4t53VtudNdREEqDkkLfNJA2hQ
|
||||
WwgLylCSqmaWL8V10OvlLG+EnT0XEIkHbzRW5XYxs+U7saG6ze5wnpPNWDb8MYj6
|
||||
4bV6V4My5o7dejDBVzhk894MtOjdrhLWCUuZ0WcZvfIm4z5c6jWuKio3VB2hcVn+
|
||||
2rtLu7LFWhlmyiX2TtB3cx1gkGpYTllQGdWkmsQMR0uxVy1KVyiotrlK5oDBuoW/
|
||||
/XhQ1pKUL9gW1PeTrUexUJBxFP+MWONOuzarDi+fGNyDCh8wgkFkYotExGUiVxjT
|
||||
9h/mc7fSVypygrWkZmtjb2gAJQRBH1GOu3fhr1MX8AXY3wtZXMWCDmoad02PZvrB
|
||||
Rnx4d4QuHqlO8LsMvyo=
|
||||
-----END CERTIFICATE-----
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICxjCCAa4CAQAwgYAxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTETMBEGA1UE
|
||||
BwwKUGxlYXNhbnRvbjEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjExMC8G
|
||||
A1UEAwwocmVsYXlzZXJ2ZXIxLUFCQ0QtMTIzNDU2LnJlbGF5LnJhZmF5LmRldjCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN51AZQAYIoAAQUkG7qFudND
|
||||
MT03FO6j+ThIsqQzqXgHOCBDVMhaWs4qKJzMD+8vtnPHzz2t0ksYsnKjYfO21C/k
|
||||
zbMz3yBZSyFA/eqEA/CLbyzECs+eaNHX7hDaVcHX22Rbi+W7zmjJE2LZ5oxGoQKn
|
||||
SQFEn/0SsjKX4DdF+Rlw4TBgBuJ77tXnslZr+Hcgrt8dOApuWZ6v5PPNaM72L1Gp
|
||||
1eP7ViUia8yc4AO2UjdO8iGSaDjy/mlWVLsK9Lb+/O5RGMmqcN+o6MndU6WMOtVg
|
||||
kjfNeIZWJ0RdmEkR/JMyOmZauyqZiW7stOVhtOxfhE5b2N7VbqtT989qOPZ/x38C
|
||||
AwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQDYnQFv2aG7pN3idts3EkuIlBlfVGKM
|
||||
V1gQjasdkdVlBVS0ehCRCXOzey3kgNtQiFF1YHZ/0uoq1abZjRCXg4EG5++mTuMk
|
||||
yIB3Yng1bEJ8A4juRrWn2ihEul7sfPfEt0lfxqn2sqN5ghC1UpbcPh6T74mbIflq
|
||||
pMdv2IDDpOzCNAOHSqjbJJTg1oCi+nMabXOtwn0pqsC1tiqROLtG8qWV1WlT59zb
|
||||
9FxDeIhT/pbZNSlwJ7akJ7ykeIhrQdSQpnclvzum0/vO0aLoojQg0UH9ldEHGu0K
|
||||
Pn+k1eX3xOD9KZn7qrgu0qZR0v+18brJ9jPTdxWKyMLhVmGX6Fzj4zIL
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA3nUBlABgigABBSQbuoW500MxPTcU7qP5OEiypDOpeAc4IENU
|
||||
yFpazioonMwP7y+2c8fPPa3SSxiycqNh87bUL+TNszPfIFlLIUD96oQD8ItvLMQK
|
||||
z55o0dfuENpVwdfbZFuL5bvOaMkTYtnmjEahAqdJAUSf/RKyMpfgN0X5GXDhMGAG
|
||||
4nvu1eeyVmv4dyCu3x04Cm5Znq/k881ozvYvUanV4/tWJSJrzJzgA7ZSN07yIZJo
|
||||
OPL+aVZUuwr0tv787lEYyapw36joyd1TpYw61WCSN814hlYnRF2YSRH8kzI6Zlq7
|
||||
KpmJbuy05WG07F+ETlvY3tVuq1P3z2o49n/HfwIDAQABAoIBAFxDMPVeNqvlloa4
|
||||
VBvHDKwXSRu3daIINfvnAthhaN8UN24CHu69sr2g9JkbdVxhcI2SiFxvdDGbO5+a
|
||||
Lazz3gtDHSE+2ULEZgmTt/wE5tFkMybg5A76B0VJBj7NHxY3XZHA+kO84b3J75Vn
|
||||
BFyXin3cPcYd3TEMCQY8wUyLY+Xtii6yrA618H/27Dhe/F04/MHchMf1VlI2zQxI
|
||||
/Yi3snIAl3YFRVb+TxQCd1LG3UvbafPRTc2zv9HiXQey7ahwbtzyikQwOZT0htJg
|
||||
iTy72nJVHq5Iel1L0/gwD/0m91QrlZlTqbfkCvRZCKNgtaf2+wJ+/HWIoLF8SlqX
|
||||
MO9DWEkCgYEA8kisxKhEoAVj4e2mQmuLSzc1zB+/kPtWCXSnc/gTvQPC2LMlwk8k
|
||||
8IRVah4SvqdgLgXXCbARRatUj43yetPZXlKF45OXFs/39abpFyFWG2Dzcwmy1gYC
|
||||
hHOFYieZWvinYs5mvBuG0qLnSpw0sTWsUvuJB+jp1M+W/6pvaw8O8fUCgYEA6wz9
|
||||
I3Q+E+KEz4o+P+PhxbFd6F3BRPIT6hDn/EOISuaZ/8Zo1t0fhzjH5TXL9ipeNKfF
|
||||
VmNE4enKg3uNAYR0PbWFWZjLRn9pG9WIKh6ws28eTxjJ8RSlHJELXsc+cLFkXtKu
|
||||
9Z3R3Fzw+j3JKTE8bXbu99WrzIv72QIu5tIbByMCgYEA3KgxqR1y+qZOFIqi/CUE
|
||||
BKmwtkpH5tvwvMXgaC8Mkv2k7EUkY3Y/N0nenLns6nR3lRK+iNUwtdnXNrLZnuHo
|
||||
Ow4/YEefuCgKNVEhQm6bBG5k6mVv2Zo5mrW3SfC0q3SAxe0jBbiwLpAsw/fFyYsP
|
||||
ebgaUfjfVXEGnax0svVQ8C0CgYBt/P77NyrRTT8OiscESJNeWdfyouSMaabN8alM
|
||||
jyFYwz2uxV5LpN9a/EP1ys2tXDgG9bbO7NbPzAG6svbRjfSC580Flw0P6RD7OFlm
|
||||
NERFQqrxIk1k5V851dl3OU7Llwa7pGTAhGAueMM+pejawLJhGrVJ/Y9NwPdRncbq
|
||||
tch19wKBgD1Ua1yiYWbKPP3l9btMwjKUJlD08+4JXCTSVKzKe/JclQ+fhnpBZZGS
|
||||
58zgrUugfpdOnzavGxs9kKVskl3nNGtpGtuWyY8fSIU/qQQXEJRcCYpcgu8bMJNI
|
||||
eAo8PrJR6BU9nGuKBBhEs+PWt1LiNaTLqU1GMMnwneqsrCwKPOlG
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIELjCCAhYCCQD0kF4yo85tTTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDEyMzE3NDM0
|
||||
NloXDTMwMDEyMDE3NDM0NlowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEOMAwGA1UE
|
||||
AwwFYWRtaW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkOPicn8J1
|
||||
BQlrZLxAX815+T9IZC/Zb/KYv1VYo+7oRGpLivJbJEb7MRJkyqCN33/1bH4B4REv
|
||||
56qF9LdLO0xMSErK9vXafqWis++HAPp1p7LSFmjRw75x7tKdzlUEkciqt3SBoxQj
|
||||
wRwlgGBMHxqlJt/DhvQ8mxodxbdyWiOzU+gDHeexZqFrmoWe498ywU/l0ollBn5P
|
||||
aaKPU39uaVcn6W2t0jkIioKKm8qiaA6bHAK3voflE/8+/6DVhVAjdacwidgHnS6z
|
||||
xCSWGvENinXBN9zZBuL0mCxCKcOJGy1NGME+8IrCEJNI2MgL+hVFvCBXW+cgtSeI
|
||||
imK/3ETfELHFAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAKr5EH4MBun6Hb1CQt7t
|
||||
LqeDZ+J1KyvMV6AUPu8v3zReOG3YjQORurKxDeK/vI3QCrJLzrAUQodJM0eGEnRu
|
||||
mG42UxUxZowKqg5uiEJVTMZEIOr8W1dpyQAEHlU7DbiarjnZAzdTSafquc0PU4uf
|
||||
sBFK//lDluyVaetNC7f1Sn61Gh0piirvIXZW7z9K+HgheK3vz4r40RkjTDm3ZBUh
|
||||
nPDU/DtkVJET/yM4VcdqggRr2XTah0CeDw6nUKB+gBw352q7upMI4KLkry/sjbQ1
|
||||
D151h2E1qkhG6gqnau+dmNcT6CKNVRQSAhLT4ULf4oc+IFvMhXi/I1Ghxqla2z3R
|
||||
5DpIi9GF/efljKujshy3FrLLjCDZgUAl0qv936T5vZAQZ9SL/iY3cIUr9nOmcfFd
|
||||
67lf040D3SJvELzEoS8bbCJ3VgBShSVc+TE5LQ0LC3DjdunWJgPAXmpKAkHhAM7P
|
||||
ftU0jaLeLlonnV8xPYMRCsitb/3Xz43VImbAcrCVA6glu0bg/5CpEBS+2fIVpBVl
|
||||
hKuVCKzDs5ei2q1H3f2ejOHy9PbCl8deAkhNwfk7RSsWaMk0CTU7WJXLindFQuQI
|
||||
G2o6d0O4AQcQYlLaIlwCgY7O+HE9YBkfLMgiA28xtw2p4sDxuYzQBPuNt/FiT7ew
|
||||
AL5fJTfMjVuWBjMr4XS84L+3
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,16 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICmjCCAYICAQAwVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEOMAwGA1UEAwwFYWRt
|
||||
aW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkOPicn8J1BQlrZLxA
|
||||
X815+T9IZC/Zb/KYv1VYo+7oRGpLivJbJEb7MRJkyqCN33/1bH4B4REv56qF9LdL
|
||||
O0xMSErK9vXafqWis++HAPp1p7LSFmjRw75x7tKdzlUEkciqt3SBoxQjwRwlgGBM
|
||||
HxqlJt/DhvQ8mxodxbdyWiOzU+gDHeexZqFrmoWe498ywU/l0ollBn5PaaKPU39u
|
||||
aVcn6W2t0jkIioKKm8qiaA6bHAK3voflE/8+/6DVhVAjdacwidgHnS6zxCSWGvEN
|
||||
inXBN9zZBuL0mCxCKcOJGy1NGME+8IrCEJNI2MgL+hVFvCBXW+cgtSeIimK/3ETf
|
||||
ELHFAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAmVSuFX+p7D/9tGfBgt9OKGn6
|
||||
N0xVc6d1gVf9ADrx1KEWjoqMnng2oe8yc5LXIfYHMZEIm9J0EigYsMEIUBDMer86
|
||||
CIXBdVN94H5gUQDIzaZ+M0+eU8vg9/K1GGFBkv6hBzV89Kps+1v3ykzsWlN7JcMM
|
||||
HZYzUTrgeSAHiQ7CjVEjUMkcAkeF23YYdSsNcpDx1+8m/ptFaaaVzhGL/2XmvPjk
|
||||
xCJDsZYX/DmHaHWcYRFUVxND9bDOEF7c6Gt+J9spHR7hUIDfeyADIlvItI2Rw4i7
|
||||
70Fg/JUCUG25KyD8BKSwBic6GAJ04g8+aE3d3FMRnPxc5iNdFJyRG/KGgNY0CQ==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA5Dj4nJ/CdQUJa2S8QF/Nefk/SGQv2W/ymL9VWKPu6ERqS4ry
|
||||
WyRG+zESZMqgjd9/9Wx+AeERL+eqhfS3SztMTEhKyvb12n6lorPvhwD6daey0hZo
|
||||
0cO+ce7Snc5VBJHIqrd0gaMUI8EcJYBgTB8apSbfw4b0PJsaHcW3clojs1PoAx3n
|
||||
sWaha5qFnuPfMsFP5dKJZQZ+T2mij1N/bmlXJ+ltrdI5CIqCipvKomgOmxwCt76H
|
||||
5RP/Pv+g1YVQI3WnMInYB50us8QklhrxDYp1wTfc2Qbi9JgsQinDiRstTRjBPvCK
|
||||
whCTSNjIC/oVRbwgV1vnILUniIpiv9xE3xCxxQIDAQABAoIBADiWj752NodBenZw
|
||||
geUMXCyUSsauYNbvVR3ew1C5RTG+VQTqLPHAawE5x6/KNkk3U8kM36mjntlb/gI9
|
||||
DX3P9Dkt662r0oYcxQE00H2PFos5y7Mf71mjyYMCjqKmWJpLc5Aw8Oh8ATBkX5BE
|
||||
5pu5UqgEnZMj0Ud9xdn//l6STyvVeGDQCEtLPn9AGZFuZL/HpXKQgr1nfmSA4gMI
|
||||
tDdDumVVlJL6efEdKF4whgS+ejGqsyJ7oB1MHWemqVtA4WYn8J2YL+XRN4JwVRJh
|
||||
Pu5aDvHFfrn+2k33nmGWVIlXFl75v1pOCzYv+Aa7Bxx4PMvyU7WZONsJ2xjiJhp2
|
||||
OLiP4LkCgYEA844zPjAI1WWVe4HViYjggJrQZl20D0JBy22wqw55eqGSWX1gON3k
|
||||
d6RapaVyThKd660Qmsdemgjr0owY/0Fr8JnM2ybL4/0MG9jBynZ27vbyLG1od9gW
|
||||
96ewn5F0oyT8HT0bicz4EZfVEeUD1sqCCRIriFSccR/qzjVjt8qY+rsCgYEA7+I1
|
||||
2oKqXSvyDxlexVsKKPXoH1fyTpk3/uU5esyDatQJ2t4xlZ0xeOcvh0WsAmHJeax1
|
||||
nNHlv6RabiBtiNME6XMXI6oCE4yYeJy7l3UAOTB568n1oIED9Phq/dkoMsjs3qx0
|
||||
qSxfhYY98LOPObiF73Iar5Qw0FPvR3alvvnNfX8CgYEA68u7LrTgiIFd1IIhk5MS
|
||||
D1BS/RgxECjMfD/JMALGd4RfpQYuF0A0ReS34fEolg+OFrKqBb+JhkWm0mPSe6YB
|
||||
86FjZLTN5v+BLqCPFg3VHYu1cG/IGWb67W/LHuF688wFzeTweVwYuyetIDMBoXzT
|
||||
oiaWQNnxz8/fyx6DWVfq/asCgYASLjvUpsiQrS74U/zpyj+X4SNJlNnJeTVUPT1B
|
||||
AFUJeK6ShvqNE0/XkPX6M56Yw56IeTikvQfDoYo1BIIot42Mv+tGCbGEl8hKg953
|
||||
2Sc+Ll1fMHxMQNry6wz41keEqdPCAKIK3FEVBpqVLpaxUjncbvJ00i9s6p+c8/IV
|
||||
6krXswKBgFfQ1lc2ffE62AcXJofw+uaNZM2+FUbaDEcjcAR/qPuRR9pGCNtnGsa+
|
||||
CkTsatI7Ip3CrqBIwcqTvl8agt+I/Fn+Zcdp956uaqyyEYvTEetFbdvaFSqf+krF
|
||||
YvOkAt3xy3Am7dmT8Qx5+FrXBkRDtfYk3xh0tAMZV1H1jiKq9qcN
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEUTCCAjkCCQD0kF4yo85tTDANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDExODE2MDA0
|
||||
NFoXDTMwMDExNTE2MDA0NFoweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEQMA4GA1UE
|
||||
AwwHZGVmYXVsdDEfMB0GCSqGSIb3DQEJARYQZGVmYXVsdEByYWZheS5jbzCCASIw
|
||||
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALDzZVMm5TvFvMxMIryQGu/uTl84
|
||||
59lCgTEX6pr7H55OPg5/ZM5w/s66+qC3Teyw98i+X3PIywUizsnVkmylcLBRDLUY
|
||||
/doo3Xp1KkTClasC2XeDIKl7zlNgIyqLLfRF0CkjdWsyFTpNi5NemezRDUBa9qXt
|
||||
6EK5qKWL5SN3kelTZk3slOhfXyr/a2mEFMfqF6SYp2vZGBfF/h8mpb02TEivaTIN
|
||||
haldIxDi0LaWXTqWfJf4UPCiHFtq78OGysA3LfFPfRvwe9WxQKbV7D88HC5H7EKA
|
||||
gYjT7AFgSvl6vCRwj+DrCw3rkS6bUDrpOItp157n1KVaiQ1wnvi0oOcbI+MCAwEA
|
||||
ATANBgkqhkiG9w0BAQsFAAOCAgEAPQg5nhu35IcKrzFw8CfmUqY+w0qvxteaaULr
|
||||
KHXJ7Fm9qoD02q+V4xxysFm2dP2R1Q+LqSzLnVIJapNQMpeAqfl4yiPZpBdPIMZK
|
||||
2LPTD/A4o/4mhADte7pUtZSc0XuuZ+ZAb7wQis9ujkUxJk5S+uy7++zK5Pvh4e3/
|
||||
b463riy8GyOIRKipgEyTeLFz/VpjkqadRUZY59N4pFA1Hr1EjZOfdiVLWKlVT1iV
|
||||
JyWijo8+SL5bt8naj8fKdnQNqZkHZSZ4Ep0lDRCxeOfNyUG27xsSPoa1ixKh+N3x
|
||||
ipB2ZWy/0k87vmLEMc4Zr13o/iLEhDp3y5NuG/djwtnzd81/RFvD7fPjf+nmAzdI
|
||||
XQe2VARmm8KeYvAEsyawQnVxx4cx/N8M+8VlF8PXS/rZGt6W3+OW2R4ko6Bi2R2K
|
||||
efb10HKFi9uhalumrmMH24XriH0hQS9cyeSRTsjjWr3HUNrFb6/uAOZCoEBqPHJh
|
||||
ohL1dwUKcxdM+ygptqIopCLNapXFbZur60V93N8SCVu+BbK02yg9AbdbaZh4vdCO
|
||||
pmiIIzTcgkirfn8Cbp22513x7P/AE0bxxZlAJB+dPpgT3c5QFLaS5ImSoDWRkhFH
|
||||
s0NBmbBYF/PkfApItiOWQU5ZNNOfn2TO94MKJMY9nNYBWT9xT45ON/qo+k50/ean
|
||||
zrh9Cy8=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICvTCCAaUCAQAweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEQMA4GA1UEAwwHZGVm
|
||||
YXVsdDEfMB0GCSqGSIb3DQEJARYQZGVmYXVsdEByYWZheS5jbzCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBALDzZVMm5TvFvMxMIryQGu/uTl8459lCgTEX
|
||||
6pr7H55OPg5/ZM5w/s66+qC3Teyw98i+X3PIywUizsnVkmylcLBRDLUY/doo3Xp1
|
||||
KkTClasC2XeDIKl7zlNgIyqLLfRF0CkjdWsyFTpNi5NemezRDUBa9qXt6EK5qKWL
|
||||
5SN3kelTZk3slOhfXyr/a2mEFMfqF6SYp2vZGBfF/h8mpb02TEivaTINhaldIxDi
|
||||
0LaWXTqWfJf4UPCiHFtq78OGysA3LfFPfRvwe9WxQKbV7D88HC5H7EKAgYjT7AFg
|
||||
Svl6vCRwj+DrCw3rkS6bUDrpOItp157n1KVaiQ1wnvi0oOcbI+MCAwEAAaAAMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQCYoAQUOBUab2qTkc7OHQU2LBBWgSbE8TZQYkqCL7HS
|
||||
jm6g5Od9sQwKC9mA5BT+PNajnzJQ0CtHvkzALo+Ep+d9JQYtW7AJKbpCuewPe4GJ
|
||||
4c3eLb7a2HQPnpMJP6ZL1h2qGraWs7+pBCi7hrZR1s/AfzpJ4uuAlhcCpvQK+FMX
|
||||
AVMwSsu1PlBAFN7irX5qMga5MWUDEzgEJ27TMOov53OT/JU6LNHYizIpY+ZORsh2
|
||||
169EhaW3xfwtB45jIRnkQegmr8gPlqY9IEn2eH8dCKZrS41iKHiZ2IZbbu2wt8rp
|
||||
/wxU7MCYm7tvw6O5oFQy04MRmEifloaBF9v8l5mNeWd7
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAsPNlUyblO8W8zEwivJAa7+5OXzjn2UKBMRfqmvsfnk4+Dn9k
|
||||
znD+zrr6oLdN7LD3yL5fc8jLBSLOydWSbKVwsFEMtRj92ijdenUqRMKVqwLZd4Mg
|
||||
qXvOU2AjKost9EXQKSN1azIVOk2Lk16Z7NENQFr2pe3oQrmopYvlI3eR6VNmTeyU
|
||||
6F9fKv9raYQUx+oXpJina9kYF8X+HyalvTZMSK9pMg2FqV0jEOLQtpZdOpZ8l/hQ
|
||||
8KIcW2rvw4bKwDct8U99G/B71bFAptXsPzwcLkfsQoCBiNPsAWBK+Xq8JHCP4OsL
|
||||
DeuRLptQOuk4i2nXnufUpVqJDXCe+LSg5xsj4wIDAQABAoIBAFP0+BNu9f7ZQE4S
|
||||
pbygBxfmEutdPaw4wMGBXn/wPL1I1GreiP7mYA/IaZgNwPxXrwlhQjrWf3VNYZ4k
|
||||
JlhEWuZdXlEirXdwQj2TD94WERtVu8bXwYyIwImQqL7L0J8A7NZIC7MzzRyfpGTk
|
||||
0tWpDseFIVfzPGtEWb9KVAry9ZklfUlj+sLiRBmFfDOJ6k+k7bSBG5BygQ7+OdSv
|
||||
UEhXpqM7l3mJKnTHBtnWNYJphQ/NNhWyilL5e5DW13VlRdWbWjLyHP49YWoqkW/3
|
||||
xo5ETI5GXDSLaEtJZzaBZ0iJ+Wq6jHusVt1htvUWgRNyTJtvVaiB8S4AFBM/79IO
|
||||
LSIPCQECgYEA55NxU3AHYG34AekzjbzL/OPVEYstA0PB9LyNazbgptHm+lMT1yc6
|
||||
7JC+Ggmrx+kgC8MsN9UOPaHWdrNeeDuBywLsqfoJ+9/h8q1RvcVcaiRzXgahgtB7
|
||||
tluEfCx5BOd888L3bLyP0LNPVR+kDk9qPokRC2S9DSP4Nz6iZc5UF4ECgYEAw50S
|
||||
U7cWADShebYjzth5t3QE4SdzBg3sVfWgp6dfm7WD58cBF17TyB/C2NYru+k9rzyk
|
||||
HodnluHvGPWTbfvvVsbuhR18CSGVevzGWDMhWHXe17qrDBFrCLBqkSENuDhh9gSJ
|
||||
0FfCP3VQ4uTn2oSczZ7Nwd421h/sFYv3pT2kjWMCgYBK1EkFVij8DuzZ6TogbcZY
|
||||
pGJANgHIkUeGRrtHzsbPAPqrHtdFacbPlIHpNgDNK1aQlnOeYvkkDzyWxKUdItVw
|
||||
/TPuRP6e5hxD55+HO9P99GNXGbts4uNm7LGl0lUUsZydw/1hpJiwLpDPB9diTGUf
|
||||
afkY/mdcbKgTaejeDsr7gQKBgFldRKYiGlb1tF9aKnmww8pfomsKDq5RZgrPMBnn
|
||||
iPIltqEIdSMsGyxt9iIBlfE+2QNZfNDFozl29jg82KGCWxEVyJnfom65fQS2vhZF
|
||||
JZK4Jpn/mWzl+DP8BHNQ2meyum4eHKelsAQ1oEJHuPRHaSs2xWEwF3UzGDOvwe8n
|
||||
filpAoGBAL69XLGVL2StuZYFXJvIclEnOrcafCtQqpu50dZ0DxXczR8OG846rttj
|
||||
3v9tcxGMaXrnBu/vOYGsvO6HuUU6ooidms1OrWnOyZTFxxH1xwv7xGlFPSb5mMAn
|
||||
FvmSU/8uwkgOuIrxKGNxKKhbNM4pYINfCe9ODhGf5qaG87zy7Ofy
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEOzCCAiMCCQD0kF4yo85tSjANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDExODE1MTU1
|
||||
MVoXDTMwMDExNTE1MTU1MVowYjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEbMBkGA1UE
|
||||
AwwSbmFtZXNwYWNlLWFkbWluLXNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEAwPyZqt6HNI1fCzhSNHvZP1ymqJJbYMyKTkVOvlIkEBMe4oWzvMZS6CUl
|
||||
q54j00SSF8bTcwLj1o5MgREzPxoqK7zCGWknkwcP7k8wIQxpA2MTWBkBlQMPVfx7
|
||||
8KojIGtjP30rBAYoYbnuZS53rV7aJl1GrOfgi0FIB49iLw20iTZARk35ntR51nRs
|
||||
s1iWD9+6+gB+kqDo4amTQDRs6TU8ltqE5bSSn1tXXn8jPP3oQX3Hkmb6ck71ztPb
|
||||
VUoh2lfu04UGmJ0+2JJDEchdRWrdUmJmASLtZF7uRtdkEQfhJiULFZsLvzNbyrQZ
|
||||
5WYLotpj+SYMam9YQi/Kh8heeXgKPQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCP
|
||||
nMyXeFZ4pU0kdMClj3IUhr8NQfHBUVWtyy8tffWT4b7xLaUtTeKXrzSAuTGt9AFa
|
||||
Eww4cO8leEt8ZqpJYoqoPsrGgxCFUannmsQoKYnHCT/+zo9KAY2I7rE4PffFcrFU
|
||||
VmlSDgeeV7pybCXXIpVV2SU+264O96Eyykl13I1t2dMrFZ7F5oSU9wOYvLgfQw79
|
||||
qzwuE2EN1vM73pAhbnShjSOKE1DXnSaXNCsdbmcUcla/6W2przU1Xx/0TrNj4esT
|
||||
Nsy5UYlf76XXQJisUryux0+htLPbUJgu5rcFj+dOakg3rI0+h1GeYSum1vhQGBeM
|
||||
NwkSgA89Lwi5zaYPzc5SOx/IVfh341xtdJYdGF9DfB0ghVJ6Z/5BaQRW2H0jxIM6
|
||||
vrhr03387GO9l7R8q1gnoklqY6KkIHq43maqKTJ6ZV/sjV16Z9yn63+f6SViFCzF
|
||||
bkXRZdypSqc8vOP8f2q/9Gbc5jPyIMVtJtDZlyHRQ93yashf6BFcP13iWutkdNbo
|
||||
fZYt1ZzC0Kwn5SQDnKGmNEzPyl4/nW0RgDNP6hYyxcL9JVzN0MSyjwajNwhDbxpN
|
||||
FKXnwhk1MMclGAcGnDZRoYbweuJS3x8ZoAP/pTrxMSGw60iwc7co54Ina3c+xHAW
|
||||
Dd8ac41yljTr1Z0o2ppiE46ozcxT9sU0pKAO9bAdnQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICpzCCAY8CAQAwYjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEbMBkGA1UEAwwSbmFt
|
||||
ZXNwYWNlLWFkbWluLXNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||
wPyZqt6HNI1fCzhSNHvZP1ymqJJbYMyKTkVOvlIkEBMe4oWzvMZS6CUlq54j00SS
|
||||
F8bTcwLj1o5MgREzPxoqK7zCGWknkwcP7k8wIQxpA2MTWBkBlQMPVfx78KojIGtj
|
||||
P30rBAYoYbnuZS53rV7aJl1GrOfgi0FIB49iLw20iTZARk35ntR51nRss1iWD9+6
|
||||
+gB+kqDo4amTQDRs6TU8ltqE5bSSn1tXXn8jPP3oQX3Hkmb6ck71ztPbVUoh2lfu
|
||||
04UGmJ0+2JJDEchdRWrdUmJmASLtZF7uRtdkEQfhJiULFZsLvzNbyrQZ5WYLotpj
|
||||
+SYMam9YQi/Kh8heeXgKPQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAI9SY580
|
||||
Th9Q4H3rUBMhdzVOW2f6Oyb4TPk0VBrVpOq2Puu50YW64UknAFz0beV5EkcjUjEo
|
||||
Gib9SKLnDuQnJk90IbjivfAqrimT0bradbHXVoteuulftRzjhFBAnwrDD5Y1eSiU
|
||||
mbKRDcp9IVPDFBhJrDgZhOoO/d7EeLETudXHNTTknxn4a9olYuAHupq+bsTif7A8
|
||||
DRWmCPC5BsNNK5w7nOC9ZcKCSvYbo0gLHzejivJl/GomYWpAXR8gV9xuJ5e3tVPx
|
||||
5CcNRCYyepRiOYwjn0nUTJpRmRHjzm2vCx2s0Z9y8cOtwHBgEWLVrpCkWm+ik1as
|
||||
EqfByEDkI4TVdKw=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAwPyZqt6HNI1fCzhSNHvZP1ymqJJbYMyKTkVOvlIkEBMe4oWz
|
||||
vMZS6CUlq54j00SSF8bTcwLj1o5MgREzPxoqK7zCGWknkwcP7k8wIQxpA2MTWBkB
|
||||
lQMPVfx78KojIGtjP30rBAYoYbnuZS53rV7aJl1GrOfgi0FIB49iLw20iTZARk35
|
||||
ntR51nRss1iWD9+6+gB+kqDo4amTQDRs6TU8ltqE5bSSn1tXXn8jPP3oQX3Hkmb6
|
||||
ck71ztPbVUoh2lfu04UGmJ0+2JJDEchdRWrdUmJmASLtZF7uRtdkEQfhJiULFZsL
|
||||
vzNbyrQZ5WYLotpj+SYMam9YQi/Kh8heeXgKPQIDAQABAoIBAC9o3sdfS4/ZexPi
|
||||
ji9ejYxHUpnu+ovZM9Durd2LiFh6mgfEGNezUQK+vXZfryVjnxBARAnpF9fJtXmv
|
||||
pAtIfjuob3aWoqY4Ae3lfklgJxwx5rqpyf21drsE/92rrl10hDlAoqSmbp0zdCFf
|
||||
PP9WYfkyyP4JKNyM+QkCbHhqwYNDZrZIJs7BATmsNoDQ0kieFYCvJlaZ3HRy9fpw
|
||||
/HIWVtJryBNbZJXLaN58lbOoJRK9h3ipsqw8NdqDDtOQsJ1lPbQwO/+FvdW3v8Cz
|
||||
1R4bGHls2ESESiaGbP9VgSt5nC0whmLyKePOHsq+xLU+k5kIPqRADzMCATE6OEhI
|
||||
8R/q/gECgYEA+OMypJwZyMIHY/FQdN/bDnEluS6zdpLW4CLJiZxCbKThYzKJxxWx
|
||||
RV20Pg0i2tCOLM2SpyvmwzVNgF/XeFxra1DKty/8K9aiibPkCbbruzRrgjSVLz0m
|
||||
tynVjSGx6xR905aRg0ZZlnMLW5Oaag1FxpcXBW/WrqTmA7+BNE7dCJ0CgYEAxoBy
|
||||
EYu7ZETePmwNS7b6FQ2VJFIt5A5W5AC/0J2+MtXBgNzmGvVX6ss3VaHdlcJORgP3
|
||||
03eGoUnRANsfyQFsn5moTsbL+/33xzmU26KXc7X0EH1sX2eDNdAy/w1wbOXBnlmR
|
||||
DoPKRi/yRs9r9axKA6XhLbpGa95c5Zb3cslrRiECgYBb2a0E5r71QfXsQlBI8Zws
|
||||
FkGvt7ZvWf2Gtg/egxZYdfjf3PTPzgef69bq13o3eqQdkLhAjYkaHX++kqA4QRM7
|
||||
hZNqS4EqxIkzfHn5w9H3Qn8yjClKR60UB5JSBU9dzDArd/O3mKzTQx277BsebEuF
|
||||
4JiUXxPBXAWu+Gu8XCZiWQKBgQCyGKw/cc8/t0pvVyLWu+TE3trhK5pg8zyidMmk
|
||||
suLjWUW0CH2r0lR/JLUQ75mPtDXmO8kuwh7YtxH+YpuyDMUYrRSFGXgLL2IQLWmR
|
||||
Zd/cwXOpF98T+huPPK2EiNpF2h5NpK6xBy2Eq6AESDXkxh/iBgJytJ5aSbevhjOd
|
||||
mXnWAQKBgBoJ2dsi12LRCaqwmnnnANKjlBnNzCzzSpcNOHte6SxDuI5x4PO1ZHa3
|
||||
JlCzAeLGYiwjQB9NXW37JDLq2FhREU3szpS6ew2+NHZdmHRZcETysC+eCyWOsZmd
|
||||
EDIqe7EdJUbHXP4MS03r6b5ROc6vRfZO15R4cGufeDohrKrYf/8Q
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to generate test certs using the custom rootCA in the code
|
||||
# Pass the name of the cert as the argument.
|
||||
KEY="star.$1.key"
|
||||
CSR="star.$1.csr"
|
||||
CRT="star.$1.crt"
|
||||
echo "***********************************"
|
||||
echo "When prompted for CN please use $1 "
|
||||
echo "***********************************"
|
||||
|
||||
openssl genrsa -out $KEY 2048
|
||||
openssl req -new -sha256 -key $KEY -out $CSR
|
||||
openssl x509 -req -in $CSR -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out $CRT -days 3650 -sha256
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFNjCCAx4CCQCUC+ovW15jKzANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDEwOTE4MjQz
|
||||
OVoXDTMwMDEwNjE4MjQzOVowXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRMw
|
||||
EQYDVQQHDApQbGVhc2FudG9uMQ4wDAYDVQQKDAVSYWZheTEMMAoGA1UECwwDRGV2
|
||||
MQ4wDAYDVQQDDAVSYWZheTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
|
||||
ALfQiTsC6u3g99OgQ6TH0t4cR66Hapaouyh9p+8J2iUMPIkZKw9Z1iyKd+n5zqBV
|
||||
lPZl2t9E821A15MjMCJOKjT3F9wuNeiBvxDTAmpyK+1Nj5OXXEbVXgVsq2uy9I+Q
|
||||
f5nX47tXiiqrmSLH1cFYWGzs7RCuK4Df8MykKkKYCIW/PAEReHFqjVlUwFaff35e
|
||||
T1b/NcGIyQfNw3MRcLRtn3BF/LvwraqV4MothqCYQoEVXfp7ON5lOvaQaPLg++F/
|
||||
I/U2aVI9iQ47glBY2t+lVXPX8TwwMFNu3k+xnJ0+NRDlkXoyDLTfLNcDKxf1wCCl
|
||||
NWw2DvtVMAyDtibsMUeXR/q3kl3UhTNupHxf3YNMIhn5NpBRHi9JEvJbe9hF2O1f
|
||||
NvIaJeafsKvT1Co5sYxokVM0vjns31qi7G5f7PvPxmHg64srV0aeXRpdOb4kLzPD
|
||||
Vlep6kmJnfCoDjNLXUQeZRrjJgU7pnba+2QVsXwaK4FUPe+fhrO2OFaDeZ78MY4z
|
||||
2QsC7rinspkvl/mwoxfyB6g/8IS3zI6Ii2LRnnqjpqw4sphnxz2gDAhnEo7Nc9A2
|
||||
Cy4I8g04Lqn4O64WP/FFUEheBWIpKPIFEzWtZvguR2zETvB+H0o3gDDfgKM5odsd
|
||||
06Ujh+C1pouMfyuTTDdNWrTDpNa9MPBsKRMM7rvm9RcnAgMBAAEwDQYJKoZIhvcN
|
||||
AQELBQADggIBABUBeOADlWbNz+FwjC4TtX5+0td4pt3sPJjS4tREYZ5lrWYlByG4
|
||||
To9Pl5AMfd7Bc9r/5tkDyk0mIvawpPBDJL8G+cAJr6SOn6Pp4puLXCoyew2U9UiX
|
||||
De+SPEeTKi/YuZjgZIO7xReat75w5ib8Zvx2GyyFKhS5fxxCtWVq2gI/UFD4j0wn
|
||||
OXwE5GUkmQRSIFcmzmuPhGwDOO2VGsd1UJF/trvH8x0wOhiJsCjtvXSnVad+Dub+
|
||||
EXGeKYCJMlfnplqERXq0mkakUT1kA6qdJ9m1cvu0bbCap8jnrfuRDkGQMkB/1UHt
|
||||
c7YRBG5y0cwa47tMlKZ1/lXkwYjMPGWqOshtm3lpIvmv+/CyxaxTdN6cs14uJpy/
|
||||
QsOmOkNuaZv+1DSwaL3bQYLHYXhm1TdcfFVZVsTVTO3ZfZH2LqORpqTjVe7JCGkZ
|
||||
09kliztztVNtT/4C+CIhY6i2zncU1lCFQkUZh9e4uyNR8Y+EjMcivMnaAVoCK8lQ
|
||||
Shj0uPSEkuYrxHFIJ9AQuTrctI53u9jBdOkjXk00NB2gwLyDRhWRUHz6KxpNMwpc
|
||||
/8jMdU/GjESFASGMPuazMns0g4NBqE4jT6tGJhL4sFmn7HOHF3g8uYZnJmTyQCny
|
||||
FQOQw3/KbgGNONiTpYnmUrlCvtZKC85awJC07G/YNxAZM0MPxo+pqgz/
|
||||
-----END CERTIFICATE-----
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIJKAIBAAKCAgEAt9CJOwLq7eD306BDpMfS3hxHrodqlqi7KH2n7wnaJQw8iRkr
|
||||
D1nWLIp36fnOoFWU9mXa30TzbUDXkyMwIk4qNPcX3C416IG/ENMCanIr7U2Pk5dc
|
||||
RtVeBWyra7L0j5B/mdfju1eKKquZIsfVwVhYbOztEK4rgN/wzKQqQpgIhb88ARF4
|
||||
cWqNWVTAVp9/fl5PVv81wYjJB83DcxFwtG2fcEX8u/CtqpXgyi2GoJhCgRVd+ns4
|
||||
3mU69pBo8uD74X8j9TZpUj2JDjuCUFja36VVc9fxPDAwU27eT7GcnT41EOWRejIM
|
||||
tN8s1wMrF/XAIKU1bDYO+1UwDIO2JuwxR5dH+reSXdSFM26kfF/dg0wiGfk2kFEe
|
||||
L0kS8lt72EXY7V828hol5p+wq9PUKjmxjGiRUzS+OezfWqLsbl/s+8/GYeDriytX
|
||||
Rp5dGl05viQvM8NWV6nqSYmd8KgOM0tdRB5lGuMmBTumdtr7ZBWxfBorgVQ975+G
|
||||
s7Y4VoN5nvwxjjPZCwLuuKeymS+X+bCjF/IHqD/whLfMjoiLYtGeeqOmrDiymGfH
|
||||
PaAMCGcSjs1z0DYLLgjyDTguqfg7rhY/8UVQSF4FYiko8gUTNa1m+C5HbMRO8H4f
|
||||
SjeAMN+Aozmh2x3TpSOH4LWmi4x/K5NMN01atMOk1r0w8GwpEwzuu+b1FycCAwEA
|
||||
AQKCAgA643BTm4ewVhaPkhSZwfrodZ7xZyjaw4vSWQ9oIXvlypnKQmntLRbUhjgM
|
||||
mZ989m4W0mLgjLKAGfn2hZtyIiCbf14BiDx1FLwlo7Rubc1s5SBOZHuHpevNSRdS
|
||||
Fa8MH3sByoyHBHCbYwZYgjUVEDykCPOaGHKPgy8eIKn5U8PHNZD/tp0jmMNYDzLf
|
||||
jZHG5mf8sx6BtlTRTzaCst+srkIaMhHaFC1PLV0q6JLs+Fq2CCZnjPqXJU9SlslI
|
||||
ppOLlrPqZ1gupNA34xDItO7KH6nUxyXd5oJU+Hv4hCpspfVSSHnm8AnqGGXBLJ6t
|
||||
ummnC8aluFvsYUpXeArvRVQ0X18LhJNm1l+hADX+9LDiowM2vKbIBHPE2lcvmnPa
|
||||
Wknqa/rjekjHn0ZmSbguOKtvWuNO9D7Q1eeWLIDa1WK4EZFgIoasXaqvG3qjXUu2
|
||||
ftBUHRddtbmN9YcxWeCCciWdzVi1SQnsIKdiLaHJJ4j4EGdVTvw7aVCsmDSNouFN
|
||||
DrH+ncBNFJPQCalAol27kPA07aO+NJUFMsfHR/JYNCyZGMVpyvutRDUmoBLNTVEy
|
||||
JZJmxrhDIOFbBjPvmhgbPN6igzZPbtcabVGJ5z4T0mg+xUdgOINfxgd/vP3i0uJe
|
||||
N4ebYH8Thbov5xVL6y8UI3Aj7uJYFZ3wIbEzQ6VfYx47ilExoQKCAQEA4W5daXLp
|
||||
reM3tA0WVpIucRUfQ8INH6V9aQNJodl9PrIaZgOy1P3yPgyWYOxBq/VmxCJevCZX
|
||||
dwd87w/D6pb+J2mUl4rHGAP1Z9NyRjGhZR2zd2l15GA2G6OF2dOol8dPg2Vy52XT
|
||||
+4P8NO2TjkZBbxdgaY7zoLdqkhFQGHQG3yVHWXxDclxvvaw1UQ/Jsqhjh76DLFP4
|
||||
8Wgh+eKdUWVcfrPLPxtCD1AqYlKMUUPTM1bMtndMzTKhLvHn7Ps7bYcg4ZljftXy
|
||||
22TDBwKDyFKY12A1+08IakJTkE+x0AT8udDucrhCcC4UDHovaMMG79JDjBzPExFR
|
||||
Td9SP4MnG/AuewKCAQEA0L194ofiET1aMfxT8NuK92hxvoxaLJjjZNiT7jlrFJpO
|
||||
+9L5gnF/sTUqyIJ5oFaMajK9uUbjB7fKAaWZ+HscRqqBbL6jP2njEcuxuCiNYEan
|
||||
Qa4XG3LOMLRE8XavVu+yrKyPqf+KeZV2sDZIHwupEPol/hMvavxKUnmfaTCc15GK
|
||||
ikV7uciNFtYW0BfkS0Od94KBbOEsZO6tFYRlbM4IqX4j06JXGA54CVpUC6pmV7l6
|
||||
heDhMpGkcG49GizeZeUd3TOmCv03ulZH66WMw+mLHInEyNuZY4jgeFbsH0NjDAvV
|
||||
aB7/dPWHP0/0YX9kwezTcUzyWyWPWtqqBTHaPIywRQKCAQAWXKFNhYWipyhuZuHx
|
||||
YnzS4NqCGSy+F+dx1E6ojG99GaO+vN0vfaVa/FqqcKUvDp/MEvC8zzzb5NVCzZiM
|
||||
m7/IXxPLWIvZWQMt8m6igefVpPWZgc+dAOI9KaJsci+GJtI/YX/dbl9x0qzg/zQk
|
||||
59kz0OjSb8jBB5C9vpPoaRIJbqQ+PzJdlMfM09lSGjPS0htVatOOQSIvqDm+lPkw
|
||||
CtL7CpC9yNFrvXMG39NleEnqDNEvxHPM4xnUE1EDVASYH9BmMJYLDeQSWVNzTY+O
|
||||
/oqEytlv/W4DRGMPrKghz2zWbeBJZvfIMvnwJuqvBLGadowWyQDNjmk3RVDeVf86
|
||||
KUAjAoIBABo5A9x2Z4703yTSZxUl72I/S7K9XQKnPkHH92WA7xPKgsud6Fxbt8fi
|
||||
PvqrcW4UEVWyBCWHYzPwAb+NNzeA979k4hdwJ3/q5Gyy4yOYbJJArfhRT3PSS1bQ
|
||||
/qw61bIdMJwCnZWklZfKj/t5BjxoMZgBZM5zSIyvHwMXZlBHnBx0myvdqLphGGBb
|
||||
Csifh71wxCJ40ZuE+he/6ByA4mD1zR7FyuhmR3ytLKU4JMDGak7w7RRueLvqkfbR
|
||||
0nk8U8AHNWY5e817nAmblzNiO7nM1/4AzKjS9YUMh+52NPmEdKfpwKhw5HSj95ab
|
||||
i77HyzeVccaU/Qk4QbcPKza12Y2ruuUCggEBAM4V3ZYWogxPyx84qPJOtbnnF6Lp
|
||||
QokJoXtGMDpVZ5kr5JqYFniJ0O6r1Uaa/GrehzRVE+AxIDZuJSGSrhDvbG4YjbU4
|
||||
PHjWOkhuUstSK9zd0Vho2LeNK4GUcNMhJeFsPFhfhPeRzlLF9QisHs6l9uiRqiPy
|
||||
/U3qOEjrPlN8Tllv9upkkJDmgb42VPLYJQ0kNYf+jDQEcipt0Ikfodq+yqveneBZ
|
||||
8gITjd7KnCcW/lJyUdGylps06AtYFu1G2M1D51cJYc38zhnJVgZ75PSlrtT4imOo
|
||||
GI6AoFe3I2WZ3HOLVmfKZ22t+lBwQ2iZ3vXCegy9o/ONUpaJO5UQlknFzEE=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+1
@@ -0,0 +1 @@
|
||||
F4905E32A3CE6D52
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
|
||||
## For refernce only
|
||||
### These are the commands to generate certificates. Also refer gencert.sh script
|
||||
|
||||
# ROOT CA
|
||||
openssl genrsa -out rootCA.key 4096
|
||||
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.crt
|
||||
|
||||
# Generate relay.rafay.dev certs
|
||||
echo "User star.kubectl.relay.rafay.dev.key as CN *.kubectl.relay.rafay.dev.key"
|
||||
openssl genrsa -out star.kubectl.relay.rafay.dev.key 2048
|
||||
openssl req -new -sha256 -key star.kubectl.relay.rafay.dev.key -out star.kubectl.relay.rafay.dev.csr
|
||||
openssl x509 -req -in star.kubectl.relay.rafay.dev.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out star.kubectl.relay.rafay.dev.crt -days 3650 -sha256
|
||||
|
||||
# Generate relay.rafay.dev certs
|
||||
echo "User star.kubectldialin.relay.rafay.dev.key as CN *.kubectldialin.relay.rafay.dev.key"
|
||||
openssl genrsa -out star.kubectldialin.relay.rafay.dev.key 2048
|
||||
openssl req -new -sha256 -key star.kubectldialin.relay.rafay.dev.key -out star.kubectldialin.relay.rafay.dev.csr
|
||||
openssl x509 -req -in star.kubectldialin.relay.rafay.dev.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out star.kubectldialin.relay.rafay.dev.crt -days 3650 -sha256
|
||||
|
||||
|
||||
# Generate relay.rafay.dev certs
|
||||
echo "User star.kubeweb.relay.rafay.dev.key as CN *.kubeweb.relay.rafay.dev.key"
|
||||
openssl genrsa -out star.kubeweb.relay.rafay.dev.key 2048
|
||||
openssl req -new -sha256 -key star.kubeweb.relay.rafay.dev.key -out star.kubeweb.relay.rafay.dev.csr
|
||||
openssl x509 -req -in star.kubeweb.relay.rafay.dev.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out star.kubeweb.relay.rafay.dev.crt -days 3650 -sha256
|
||||
|
||||
# Generate relay.rafay.dev certs
|
||||
echo "User star.kubewebdialin.relay.rafay.dev.key as CN *.kubewebdialin.relay.rafay.dev.key"
|
||||
openssl genrsa -out star.kubewebdialin.relay.rafay.dev.key 2048
|
||||
openssl req -new -sha256 -key star.kubewebdialin.relay.rafay.dev.key -out star.kubewebdialin.relay.rafay.dev.csr
|
||||
openssl x509 -req -in star.kubewebdialin.relay.rafay.dev.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out star.kubewebdialin.relay.rafay.dev.crt -days 3650 -sha256
|
||||
|
||||
# Generate relayserver1 client certs
|
||||
echo "User relayserver1-ABCD-123456 as CN"
|
||||
openssl genrsa -out relayserver1-ABCD-123456.relay.rafay.dev.key 2048
|
||||
openssl req -new -sha256 -key relayserver1-ABCD-123456.relay.rafay.dev.key -out relayserver1-ABCD-123456.relay.rafay.dev.csr
|
||||
openssl x509 -req -in relayserver1-ABCD-123456.relay.rafay.dev.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out relayserver1-ABCD-123456.relay.rafay.dev.crt -days 3650 -sha256
|
||||
|
||||
|
||||
# Generate relayserver2 client certs
|
||||
echo "User relayserver2-ABCD-123456 as CN"
|
||||
openssl genrsa -out relayserver2-ABCD-123456.relay.rafay.dev.key 2048
|
||||
openssl req -new -sha256 -key relayserver2-ABCD-123456.relay.rafay.dev.key -out relayserver2-ABCD-123456.relay.rafay.dev.csr
|
||||
openssl x509 -req -in relayserver2-ABCD-123456.relay.rafay.dev.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out relayserver2-ABCD-123456.relay.rafay.dev.crt -days 3650 -sha256
|
||||
|
||||
|
||||
# Generate relayclient1 client certs
|
||||
echo "User relayclient1-ABCD-123456 as CN"
|
||||
openssl genrsa -out relayclient1-ABCD-123456.relay.rafay.dev.key 2048
|
||||
openssl req -new -sha256 -key relayclient1-ABCD-123456.relay.rafay.dev.key -out relayclient1-ABCD-123456.relay.rafay.dev.csr
|
||||
openssl x509 -req -in relayclient1-ABCD-123456.relay.rafay.dev.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out relayclient1-ABCD-123456.relay.rafay.dev.crt -days 3650 -sha256
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
CB6AAE2A400B8C7E
|
||||
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEQDCCAigCCQD0kF4yo85tQjANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDEwOTE5MDE0
|
||||
MVoXDTMwMDEwNjE5MDE0MVowZzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRMw
|
||||
EQYDVQQHDApQbGVhc2FudG9uMQ4wDAYDVQQKDAVSYWZheTEMMAoGA1UECwwDRGV2
|
||||
MRgwFgYDVQQDDA9yZWxheS5yYWZheS5kZXYwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
||||
DwAwggEKAoIBAQC3xFSCk12MhfqrREW1UpGHbnFQ3Icl65TN+H99rueD7eL0CXf4
|
||||
bRp4V3ncQk35HHVBn6FaSbplXfNNFq9YSxfT+GGW07AHkUryubVQSrjH4GfCn9gW
|
||||
ngxM1cslAiJNULmkFG9y6xIK56auQl8xbf1qGKjuAXh6c5AKmCIx4Zyq26ucdvTY
|
||||
a0kOmBEjdMFA/5hiAvOsAlUt8fSC6TnJ4eL4XZNrRpbbTVyJ3m4yFmWv1Az1hTRJ
|
||||
ZYbTFiOEgPBi/FxUSkaCt7rsY+JSjKIsYJH3/Lo4kvH1X+9QuA/r7ZCzx+mKxCEi
|
||||
qRddbintLMqCkuYCH12XVAmLeElCLEOqOUk3AgMBAAEwDQYJKoZIhvcNAQELBQAD
|
||||
ggIBAF89TL54hR3mvAiegldIajkVW2QYFCkbKhH1/E2m5jEzdA0dqJk9lJgtIJGb
|
||||
vXBGopVRDad6lBqyOfC/E0QrwXt36fEUQZtU8KIc+21XzcICPcmh9ro5LecDmo+e
|
||||
CME7xuzbpYBH9s8jWL5FykU7UlZ2ETg1BTj8kHIPRV3WkVHb34/M2CREOdnikKfF
|
||||
oU3R+PmoOjOb/zVSbc9cPe9Wa75cp9moortM7SzE+be7Ah8uTYlydleRYlQ96PTM
|
||||
Sd4Vx8qMyRgEYgQTzMhMeba9XTtJpeojmdWM5GsR+TBPhqhGSrDY1qcfMYj2Vxrf
|
||||
YusIfB/hlnrk6s0cS5b0EoIstCi8/Xo++rU0HcU8GSSzU3+wvgcgfH9v+qeFK1XF
|
||||
zr3cKsakdvwwdllk1Ko8nIttpPXfG4h2vyt82hwbesz7qJ/LcUtTUkDKa9ap+r+0
|
||||
bioO1YIio6bVwWd4e4i6HekKVv/+Jbrq516cJVpYsmkviRQsbIqmPMxAjTuFnJ2w
|
||||
GPF49oUbbByUeEqsRb0R/vVEeuJek01QRLkiBhwrZySBzfhpoNprXljmPMw1w8zh
|
||||
YMGsEp57a9HC5A6kYL7d8fnw8xjDqcv7FU4VFtwYqm3CLJRhQTMr5+3EnH4xJel2
|
||||
z7F85OoCigjIN7a4iU//JeZZB/tfhjaot2g+5gWWKFG2EivL
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICrDCCAZQCAQAwZzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRMwEQYDVQQH
|
||||
DApQbGVhc2FudG9uMQ4wDAYDVQQKDAVSYWZheTEMMAoGA1UECwwDRGV2MRgwFgYD
|
||||
VQQDDA9yZWxheS5yYWZheS5kZXYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQC3xFSCk12MhfqrREW1UpGHbnFQ3Icl65TN+H99rueD7eL0CXf4bRp4V3nc
|
||||
Qk35HHVBn6FaSbplXfNNFq9YSxfT+GGW07AHkUryubVQSrjH4GfCn9gWngxM1csl
|
||||
AiJNULmkFG9y6xIK56auQl8xbf1qGKjuAXh6c5AKmCIx4Zyq26ucdvTYa0kOmBEj
|
||||
dMFA/5hiAvOsAlUt8fSC6TnJ4eL4XZNrRpbbTVyJ3m4yFmWv1Az1hTRJZYbTFiOE
|
||||
gPBi/FxUSkaCt7rsY+JSjKIsYJH3/Lo4kvH1X+9QuA/r7ZCzx+mKxCEiqRddbint
|
||||
LMqCkuYCH12XVAmLeElCLEOqOUk3AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEA
|
||||
DWm2eXew675cXj5pdsL4mKLnpQjSy+3Ewdg+NRQw8VUF12xjxVNUCPcrX2wcrHx6
|
||||
1KqCxOKr5b3d1SlqAKVwEh+6J5+A/nbfFSxT2gUmqy1IEe+obYSvj6AiN9D528rw
|
||||
e7MKlwBi6ARgyIT3HjC95gKehX6qrifNiY0aNnP/BfaCXNxPfP8Ltyfqswv9+P26
|
||||
kHePUcVBLOA6+SKimVvYqhAtLhaqjpjBo4JeX+MB/tP+kzAb06wBQOb84SILOBEy
|
||||
aOMSF1uR0peB92zxLqblhJMoyZc/rOH6zE3PHjNPiPcX9BFJJ8LHGLXPAxoR44SX
|
||||
flK/mNcmRPVplIyJ57OB2w==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAt8RUgpNdjIX6q0RFtVKRh25xUNyHJeuUzfh/fa7ng+3i9Al3
|
||||
+G0aeFd53EJN+Rx1QZ+hWkm6ZV3zTRavWEsX0/hhltOwB5FK8rm1UEq4x+Bnwp/Y
|
||||
Fp4MTNXLJQIiTVC5pBRvcusSCuemrkJfMW39ahio7gF4enOQCpgiMeGcqturnHb0
|
||||
2GtJDpgRI3TBQP+YYgLzrAJVLfH0guk5yeHi+F2Ta0aW201cid5uMhZlr9QM9YU0
|
||||
SWWG0xYjhIDwYvxcVEpGgre67GPiUoyiLGCR9/y6OJLx9V/vULgP6+2Qs8fpisQh
|
||||
IqkXXW4p7SzKgpLmAh9dl1QJi3hJQixDqjlJNwIDAQABAoIBAQCn/dOf1qWzW5tu
|
||||
y6fJ/aRKIV13pVHrCXRr4lpyA91jDqnlm25P7TVAg/9Dql1reGd8yTgQuMur9PoB
|
||||
I9bBqUwsG6ji37vQ/zJ7t+cXcmd/WRahpcw9yNfHub3OpCfFdCFw7LmBXYGN9Hy8
|
||||
WrJ5FmqOfeKYSUHg9xnbhX3lCbFVwpI4KE7WXuvZH+7A+hJl6UFXm0nMGDWscylI
|
||||
5MUS6QPoQZ0eMR2I3XgX9MrspdSzGdg8mTPIfyK3Di1RfbJEXba7HqlVk04r1PtP
|
||||
LXQfftRpZVrpRt1CpzHoJy0sxl/iuqWtWSHJ0KxvyxZpaZMOmjPiAkvQ9cw5hA84
|
||||
POWfLXLBAoGBAPG20UqKH1pbeFN6Ne5XCYQJbqDw5nbreDHcfZp8cZ8NClf5Yn15
|
||||
XRax7eK54awYyW5sR64dTqT66lUncO1MKItbSiuIJ8Yji50oObYD/r3jLhmTXtei
|
||||
I5sNIrOM/eTEaQtKgX6wUHnKrsaDExP1AcOXQB3z1S1xiog2HxGD8Z7hAoGBAMKg
|
||||
wn/gU9y3/NOf724KiS00+nEmFnjuW6MFZFhx0qKLNLeSfjgUdd5WMdDCO4fGjhKT
|
||||
gajpvQ73btFrjnfpsRW8DHCKV4lZCWV0q8Lhd7GdP9xf/Yete93I712yGFfxxQ0T
|
||||
Gp8eQ6atUJ5McQryx84zLUzPrQDPMDnguiAAc2MXAoGAUNlmnfkfTZjk4X8yRNuG
|
||||
Ck0hXOHXJJXUaVEoDiFr29h/yjdXU0Lh+TJgsIKeUnMkBTRgsYOKB7MJ6Ju9sRHV
|
||||
Se+qGm97ZlIDY/jNfO1PKvKvO8zIX3YTVMyK++XAEuIDhMxSDi8pa+N4nFvBaN59
|
||||
zY9s2dfySTX+MVtw/unUSuECgYEAri5pY0BETVhr8IlGIllTgx3StMi9e+T2JeOB
|
||||
dpYHSGkE+PUl+NJ22lCRrJ7n4A+WvpE8jQsCpA5VIx77Fd4TGbx99YoZ5VXFzwKn
|
||||
ZXWbRV3R9UwC/hYIsOhPMK9ekfZRv+3E+XqAWP7rE4Cd+opkvumWNRP3ZK4IHwQ8
|
||||
Dr/YhGkCgYBTWyOAS2D/xa3lgFbsErh+k+BgvyfwvLfLmEugwqioiWn59oUvA6At
|
||||
MCiB1eTbq8CzUZGElZCH1vQjzvL475iSZtXHD7qN3OHp6iUzF0Sw0SV/ptwMnQXN
|
||||
mMQtu9hlonPCwklIfHVvhTAu+eaYFpIkZnrbwxlcEcLeFk8EZM9VRg==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEQjCCAioCCQD0kF4yo85tRzANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDExNTAwMDMw
|
||||
N1oXDTMwMDExMjAwMDMwN1owaTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEiMCAGA1UE
|
||||
AwwZKi5rdWJlY3RsLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAO7cbcZP2XZZ6djdO+RyjH4NOpqaxURgLPosXVYr2mTduizA
|
||||
jtxAS4sZPfdZk9wQY7RT7hVoOQY836kjiiyjwuy2BhhiYjc4ovzGR25bNwi3I6bW
|
||||
QN8EHF5KIySB2gXgn9br5LgDz6chZwcWYfyqWcbJQ2oesYQIeOCsSkm1cNA1U6J5
|
||||
gAu6t8Pe9nbaLiH2t38QnVmRbCoNYUpzUNQ5shrM+AfJ8CRZtahkd8ucBPly4T/9
|
||||
dbjIjV+f8KqRTfbT932KkKLREyOhugfuFJ//YH5XETr38EcdHJ0i9Hx9P+D7+Mou
|
||||
X7o9+quX9qBDPkVSJZRREmwHw0y3ZkvK9VtRbqMCAwEAATANBgkqhkiG9w0BAQsF
|
||||
AAOCAgEAAZ1vLleh+w+6SCNiMmuwYFyIQ1hEv5GlMR47Tz0P6iJdLAaCTU0zBihM
|
||||
ChNjoy0C3OmzKmmlAv02r8GCzkDLAvcfh5T3QbF9fDDhAGKqoOZXFsUiYn1gx4o6
|
||||
8UgWI7Y6golreD7VWEa0FCctoi2TFsmWgAPtaY9EJKUsPpt+2Awtb1ZJ27xEcYfI
|
||||
gNN7ZZe3KwropMiFjCdIT1Uy/99TDiv8z/w1RYH0WeMBQLATED3flYewyLg962z6
|
||||
tkTooS5tvbtpbxtrkjBsKkktHo8wxacVvcDO8VuOnZJZC4JCn5CFgBYkdBUBpQSo
|
||||
R+bI+ldroxSgcUndNGwnNWJt7C47p1WUMohR7Uqf9uuCYFuy9tJMA9LN1nyRRKV5
|
||||
D2/N2pwias89+Rk4PNg03jAeJRoCQsV6zMMMd/Waryg04ujWUnBpLR3ZyOLL82sN
|
||||
lIpTed3+2aR1F6dK/dE3n5AFNcZ3HTvPNpgYL96IjLxPyInMSBQ8tvzmIrESMRXt
|
||||
ypBRFg8iU5Ri0crB/aHxmqerjDHbwvLLU62424uR24IJK+nRIkYdrthqaCFsCT6u
|
||||
JcHi2dfy+s9aCjhSmu1BxIXgJCV6tItQ+dwGmRVMQnQC5VBqgPm3UUdTa+rs3pwo
|
||||
0VYyQi1QDQWftJv2Y/rvtLv/OUws+aCk0AkjjohTo9kBkxsD1zI=
|
||||
-----END CERTIFICATE-----
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICrjCCAZYCAQAwaTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEiMCAGA1UEAwwZKi5r
|
||||
dWJlY3RsLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAO7cbcZP2XZZ6djdO+RyjH4NOpqaxURgLPosXVYr2mTduizAjtxAS4sZ
|
||||
PfdZk9wQY7RT7hVoOQY836kjiiyjwuy2BhhiYjc4ovzGR25bNwi3I6bWQN8EHF5K
|
||||
IySB2gXgn9br5LgDz6chZwcWYfyqWcbJQ2oesYQIeOCsSkm1cNA1U6J5gAu6t8Pe
|
||||
9nbaLiH2t38QnVmRbCoNYUpzUNQ5shrM+AfJ8CRZtahkd8ucBPly4T/9dbjIjV+f
|
||||
8KqRTfbT932KkKLREyOhugfuFJ//YH5XETr38EcdHJ0i9Hx9P+D7+MouX7o9+quX
|
||||
9qBDPkVSJZRREmwHw0y3ZkvK9VtRbqMCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQAPkDdgYNELjqRgveMqBVBafxbuRAR4AdAzPDbCLOBDva5WiSkiOOKAhLBbspal
|
||||
xkeOdAg0KkUhSX/J+l1yKpP7AnitpTEG/sJog7SXv4/Pk5oaPYwMKpHfqXKjcgBE
|
||||
QrtPBgDmQbyQwTkcc4f77TvUb9dv+dXK8UGjcjcnDlKdnG6XdyGDFInLjfR8SE3/
|
||||
u2CQ7fKZIO3Z7G1IsI3YKlK3oVTWtquhQvL/YY8hhT80xMItHJ4GL9eFQYT7NFvE
|
||||
xQHXsfLuIhlG50wT/Ce/YXmpndOX13FppfgkXUC7zpGtiecX+oOa2ybT+wkZ2kHP
|
||||
/ouZqrH4LUzSK4ufip6Xip5B
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA7txtxk/Zdlnp2N075HKMfg06mprFRGAs+ixdVivaZN26LMCO
|
||||
3EBLixk991mT3BBjtFPuFWg5BjzfqSOKLKPC7LYGGGJiNzii/MZHbls3CLcjptZA
|
||||
3wQcXkojJIHaBeCf1uvkuAPPpyFnBxZh/KpZxslDah6xhAh44KxKSbVw0DVTonmA
|
||||
C7q3w972dtouIfa3fxCdWZFsKg1hSnNQ1DmyGsz4B8nwJFm1qGR3y5wE+XLhP/11
|
||||
uMiNX5/wqpFN9tP3fYqQotETI6G6B+4Un/9gflcROvfwRx0cnSL0fH0/4Pv4yi5f
|
||||
uj36q5f2oEM+RVIllFESbAfDTLdmS8r1W1FuowIDAQABAoIBAGiWbBqha/6+b/5d
|
||||
IJRu88Vd1YNMsYO2+Pqx4kyQ9xejXpmp1uPp4yoM620a8/sv0fhrp5wH/rAUh3pv
|
||||
7ViOfBNZwGF88rRrQDKePzi7B+XxCtNKjS0Zh7Jhk/GwSd649EQPFh7czFfJ8GrS
|
||||
CiWwEY9RIQueVOwTKZp21jBgGf2QA3jcedOgS36q2zRGU23uBFLGVMNsY+lXx3TZ
|
||||
DqDwckWWLtUfI2PqU5tKhUUcBlSQYKk3WL2C6otVly56u4C+Q4TPE/PSq7sH4n1H
|
||||
1q2GGhX3gmp92V+HZ4HJiuY4xXw4QRycKSfcGvIF1ZKGcA/Dl+STv3TvY8nfS0AW
|
||||
18VFyYECgYEA+FSz4N6RzN3ndn9t6dp/gw0PX6HlrjXnW3rphOuJMkuj9LOinusD
|
||||
K/xrnpIoPvfh/QXWuebqBhw0LTgGMA3yYW63nr+te5/N+A0VytcGD6Htp01IYzt9
|
||||
n1V7fAbB4CDFM/NLBEzNsbJT6308eVR9e53lvJxT+sizz24gFFc2VisCgYEA9jzb
|
||||
ppkM8uafsxMHbNmduVO4hTagL6obKuGXCkR6X38m1R+k6/7oRvaRty9OarhaY/aQ
|
||||
oKgDtgaKyVWxft5yEe1B6qczlRvhxKVTAd5py++Yg4gyaCvNrHGuWfzM5c7vo1Lz
|
||||
k+puDC8kbkPSATEsPI15gGmVce8cc4s3wyWrxWkCgYAzRHlmYUzEeMOCaUht0Rgm
|
||||
HBoiajAayTIcZsGzGVVXttoAeN2H5YjgGdq2AAKjDVXwgLYV5yBFZqk29KwCW77A
|
||||
crUh5vyP2ywQm9L173Jm481GjuP06KFEtccqkdKQzPMpiH7iQmDs4J4GrfJAMjs9
|
||||
vBlj2PpVef31Qw0IZgDnxQKBgQD1SIw4+S6369nbZTI5UNFXojklodORh26Gma9+
|
||||
T9ZiuGNzW5FKcGLrBYUDqEEB9+A6wYsyLgt8UCoCArXLvkR87Q2DdMjiWKLd4x27
|
||||
t9VFi8cuBwbHVBMOGzPlefiVVzzJQcFXb+fthSxSFobkHxqEuxz0OLjghKKfymdi
|
||||
omzoOQKBgQCn0i7HSy8nZsGbq3ApNYfit2hfcGK2cfihvMbSunx1myk4UDFjiExf
|
||||
tKnycpLriTsKYQ+3Jj9zO8+QqjPxb19XkTAWKZ5HYQEwS19f+mPwMWyn8mvwOruL
|
||||
FDk16um5sMM1kVwStMnlg7TxCZwrT3dXHPQuZj+qHcJnacrt8JBqEw==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIESDCCAjACCQD0kF4yo85tSDANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDExNTAwMDQw
|
||||
NloXDTMwMDExMjAwMDQwNlowbzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEoMCYGA1UE
|
||||
AwwfKi5rdWJlY3RsZGlhbGluLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBANU/MiB/kLKlcMhMtXuKIGu2riYUfmfUIz2MQNo+
|
||||
oz4wQHUGg9P1sO3KT+kzfOFN7EkAzwryCIT3GEKTYoVY5X+Cllow3+IhtovgHhhr
|
||||
R9vSDBf6QSWqsVbai7U6jGQwtr9D+4Tv8O0vXtUWnTylE95/2Ecdf+n/7US435Rm
|
||||
9eg/CCsdgPw/m/WTPA9mU7xrpou5Pwbb+TiCJsnQKbEGGuFilBdBLNZkj0qOAUMl
|
||||
YBu7A7n2yIljC5zJ93dlLX0kdssSiDwt0KcXwrWs7vhXxrnTRx6sEneloa10pbG2
|
||||
0BPoqleGKk6LOy6237H5wJmJ2Feh2Kcl/o9Au5vZ1GvksRcCAwEAATANBgkqhkiG
|
||||
9w0BAQsFAAOCAgEAhhUNQL+cxlA3ZAOuySKyNaYFkVKEjoo+0hPpMzxUl1TkHRIE
|
||||
OllT5LzwjduFEvZRTE5aMiDpEUTM5XGw0zKd26Q9SC/vOnBwYl19oFhwyZ93bz2d
|
||||
15eoyEYQOZf+VKmTEVw96epMrt98mACPO3hrGGtszW1zGEMRfcHZwIMHSM9INAGS
|
||||
Rtjx5Ul0HR/srTZlc6kTpeLnnoBKO7TuPwqEav7MA7MWT62UGst0pz72o1B41sEY
|
||||
rBIeJyGoFVg0NnET0nFBQcZqipdDjSWfUiDcMxOSve0s9IOpdLYtcMdark41gAXp
|
||||
qY+Hy1uVXQx6UFJysbKaRZwgx4C/MnD/zs2a/LmGXdt1+7/AlrP7HG8NKkYCkf2o
|
||||
mSs3ALgmt5wQ/DTwfVZM/6EPmnq1rU8s44DST0CDTlpVeYq0PkuweAQYYYgHBzc+
|
||||
hjx5b8k9xiqudhTveYCuV4AlIGTdIGbsK1F7HSnNE5S84dwcvcFL025TQyc3mEkK
|
||||
HOdtGqBTZkxrehHSZs+Q17KwfrYx8Ad4OX/hXsszly4sgvV41jAcAN37hQCMbNkk
|
||||
KlsaYXnsSDSkCt/jjh127hWaTzXJnCaQg9zijvlE8/ufYXoKW3+yCSBGrVt6cQ6d
|
||||
/o1jnGh7D8mgLjTCR98trHaV2XZT8YiAPGbqf0RWmYdm2v/zubYl2Nor9KA=
|
||||
-----END CERTIFICATE-----
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICtDCCAZwCAQAwbzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEoMCYGA1UEAwwfKi5r
|
||||
dWJlY3RsZGlhbGluLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBANU/MiB/kLKlcMhMtXuKIGu2riYUfmfUIz2MQNo+oz4wQHUG
|
||||
g9P1sO3KT+kzfOFN7EkAzwryCIT3GEKTYoVY5X+Cllow3+IhtovgHhhrR9vSDBf6
|
||||
QSWqsVbai7U6jGQwtr9D+4Tv8O0vXtUWnTylE95/2Ecdf+n/7US435Rm9eg/CCsd
|
||||
gPw/m/WTPA9mU7xrpou5Pwbb+TiCJsnQKbEGGuFilBdBLNZkj0qOAUMlYBu7A7n2
|
||||
yIljC5zJ93dlLX0kdssSiDwt0KcXwrWs7vhXxrnTRx6sEneloa10pbG20BPoqleG
|
||||
Kk6LOy6237H5wJmJ2Feh2Kcl/o9Au5vZ1GvksRcCAwEAAaAAMA0GCSqGSIb3DQEB
|
||||
CwUAA4IBAQAtZX8bZMGTkScmCE41UCNdAOXEb8NfnOXJW1TrnkLCgpl6fSen1g3N
|
||||
/2GDyB4VZ6/F93DKBZY1zqQxr6V/qhwSyCOcM/1Kw0CvBP00QYhrVe0POFUOHpnB
|
||||
nvGKjSy+5oRXN1F0VHJ3smy4WsPGAyRnFwsVxVKlArYAJe0Pu4zsNnopam/M8Bkl
|
||||
CBwmmiTeBOqw+ue1P+uQ1R2J+V00oimhZoYqSYEfOhWkBw+lNp4z9iyFmYT028jD
|
||||
kAsSeE5wBYWdF9lW63EqxvnZyY4bVq4K6FIOH2Ddf7mFkuXDp2V9/Xc47rwdbVSd
|
||||
T3ImNZgN6u0fiSmNAQH8ydvGKOhX2mM8
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA1T8yIH+QsqVwyEy1e4oga7auJhR+Z9QjPYxA2j6jPjBAdQaD
|
||||
0/Ww7cpP6TN84U3sSQDPCvIIhPcYQpNihVjlf4KWWjDf4iG2i+AeGGtH29IMF/pB
|
||||
JaqxVtqLtTqMZDC2v0P7hO/w7S9e1RadPKUT3n/YRx1/6f/tRLjflGb16D8IKx2A
|
||||
/D+b9ZM8D2ZTvGumi7k/Btv5OIImydApsQYa4WKUF0Es1mSPSo4BQyVgG7sDufbI
|
||||
iWMLnMn3d2UtfSR2yxKIPC3QpxfCtazu+FfGudNHHqwSd6WhrXSlsbbQE+iqV4Yq
|
||||
Tos7LrbfsfnAmYnYV6HYpyX+j0C7m9nUa+SxFwIDAQABAoIBAC63961zBSp+YGUh
|
||||
mSkFq/CtRx4Eo2Tv7wCO965Yxr7bJ2P8F2majDasejFnHFboEXo0+Sc2u3MWB3Se
|
||||
gZkhTrZOz83Wo1YReMLQSQekiUu5ivi91QQBj3St0KnVt+hDW+YvaK1JPAlatXYN
|
||||
zEj7CY1XiPSbm+iSL1M9BY6nt/w3XJOUm+Zna+aNsUXhsyUBRb7tcXmG2HEQk1HF
|
||||
oyXHngRk+OncjFYTeOfZV4srbz1+lp+dA2+eaTqbHlRbgRkXU4lT0uqTziTVH5nK
|
||||
QFHvIoflYP0ScmmE0TmCvo2h47K8aCEHfnaaZVd40bh/32SzYzjlziSFB2GQEKNg
|
||||
bfnCfqECgYEA76z1NmXmdOE5OXPqa5sFsK/rjQZmRaN3YM/62CwAzj5wKi2oYLLW
|
||||
XbNwDbyHsutdqIVArUq7kU+QTWvuXsFm3QcEd8H7CS9y4aS8Y6XXLzxp8xWPyDSP
|
||||
O7+RSCQKzAyCZJ/8SoFcVs+Jv1/QJ8Pfj6TYBe64vrdAUt5Ib2lrbp8CgYEA48Vr
|
||||
cpRKxsNygusF7TebVFE1kIALQh11GnJ8+SplZ88TaUF4vGbiVTDOJ++v7UnLAeAG
|
||||
v+jJ6OZFGCKcMEBsG3vR8CCAbs5qte/+KgoopaDb0LqiRbLAVqAdfUigi5hs0XoR
|
||||
df9ypW9c44iWE0eDIZMj2FAsR4kh7PDBi+kuwokCgYAgvBe1uU8zkXtWXH2c+sxZ
|
||||
KH3cgg4/3qa0Y1OYaNInWSHKsPe5VVOv8o0QYzqJdloRZTnDMVzS6PIFkQM6j+Gz
|
||||
uHykuqrFw2RGa1CLr5/nRLIX0E8WAg+6El0OZFXRLrg0dCFqL6bj+G6Q484zUC5d
|
||||
mR8kGEnFSpQPfWqZROW2cwKBgAgwLLCtzBJhLFiwgkII4biiQr6zG7SAwpj0zLFY
|
||||
aNTWiOgbxm9fc3uEiaS95SEuqfGjUBrOD5Qj0xAPDnZdmoVSajWrtXJGUWfA/O4d
|
||||
92Ac7EoQq4y95FQ45VZ/qeXa0O6m6MHJMSHpYvl7C4od5ATs+TjpiO35bBLMhOi2
|
||||
tUuhAoGBANHsvkzWxXGxwJ+H2dRbh4DLHqMYehgP+2Bt/goTD13MWPDt12ptM1QV
|
||||
QmIhX4YHwybdJUilMiH4jpA6b9zd2lUPWmILKp1MeHczE3RJioQoJ8cRackWmbi1
|
||||
n856DbUV34dSStyw8cSQMb6dwIgAP6JyebaVcFQwCe/K2OPsMyPb
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEQjCCAioCCQD0kF4yo85tRjANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDExNDIzNTk1
|
||||
M1oXDTMwMDExMTIzNTk1M1owaTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEiMCAGA1UE
|
||||
AwwZKi5rdWJld2ViLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBALk/RVVcU7Di4xwE3Y2/pKyZbDQBvZ5YZy4LYT6WsWtGdKFT
|
||||
tBNJUSJDjQlVq+g75X5mbf53EDP5VKJkrOd8v326NOlXTUVdEyUcHGUB7xrY4oFg
|
||||
owG00fiuaDWRRVrOK01jrW2cmZ3tzqpHw998uO3gwLGiE/CL8xjcdWRl/zX3WqY3
|
||||
oVzmfSxTIdvMVAb+fiU/rlXUp9zNamYe5vG8P9XvNk8lf7pvgBNSb3pWlQoU7A41
|
||||
HLm0gqy+yauEvGq/nbbVyXQ7VAV7XxwoHEu2wabSC4iTfMHCx2sVd8P3WvBuBDf5
|
||||
4InwSW87NUJvtwzIRqlKcO1l1q2xWvWFeNUPc2cCAwEAATANBgkqhkiG9w0BAQsF
|
||||
AAOCAgEArVNrGgaiHYQKIfs91Vor/A9GPRsj6o4VavCRiEjaBuPSq5G0v1fb8m9Z
|
||||
B541y27N2QPdbYza2TdNqt22E4DcPXCi/JPSM73BLml3mw6ZuSLw+ghFFx3ZMN8X
|
||||
RPknim1q9gmLbEU0zMy9kgjCY0OrUpmgfEE0DVQ5MxVovdz3B4QZ38hrKgwvYPyB
|
||||
UBB5ovZYjPmaQPeRu0Cht9eSIm27c2/qAUrYNUWjmAVgrOQvKbIc+uBaj8at/7K2
|
||||
b6tOi6zyNdL+Mn6LpN+0tfz6H4NToROPXMaHXudoOMmYq2AHF9Ad8PjNsHZd30c7
|
||||
0muL2FEzD3t0P/9i80UNeKKTlY1BjOQ/npAxEoFoTpPSF58soLzO4GyXPIHZBkXa
|
||||
DETmziyA18e+1vytyx2nMrC1qMc9tziZlWzOOL5THk1/plPaIoLD+rtPM2VwxBdH
|
||||
W5mY7gSoqFDXQG/qaeLzF9uqFI32zmLHBcn6aMA6kiBkYK1HBcS48cC1LMvd/3lE
|
||||
FTOdzhPzlRD2TZZDBsFXqDtP22oPBCwUMQDguvgajQGkUIlloipiba91LNIVLLGu
|
||||
hmij1F43nXsygAXFNca9trXESPImataLvi15Gb+dad8ca0zfifncH/+ph4LtqsqI
|
||||
trHkz7EhmlNVAKRSzExbcUPczzOGU3Ng7yoxezuVDnc1+2+6pec=
|
||||
-----END CERTIFICATE-----
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICrjCCAZYCAQAwaTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEiMCAGA1UEAwwZKi5r
|
||||
dWJld2ViLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBALk/RVVcU7Di4xwE3Y2/pKyZbDQBvZ5YZy4LYT6WsWtGdKFTtBNJUSJD
|
||||
jQlVq+g75X5mbf53EDP5VKJkrOd8v326NOlXTUVdEyUcHGUB7xrY4oFgowG00fiu
|
||||
aDWRRVrOK01jrW2cmZ3tzqpHw998uO3gwLGiE/CL8xjcdWRl/zX3WqY3oVzmfSxT
|
||||
IdvMVAb+fiU/rlXUp9zNamYe5vG8P9XvNk8lf7pvgBNSb3pWlQoU7A41HLm0gqy+
|
||||
yauEvGq/nbbVyXQ7VAV7XxwoHEu2wabSC4iTfMHCx2sVd8P3WvBuBDf54InwSW87
|
||||
NUJvtwzIRqlKcO1l1q2xWvWFeNUPc2cCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQBH/vo7xzWwV3skhCW1rE/GCjPakEEBFypoNtQ3qDOGvY5c1W3QHQAXETVE2XYA
|
||||
9rBEZe91RM05W1Bwxf1Abiddq7hGWcttqsQfKbvinRnya/tmNyv1nHNkpjkQIhrd
|
||||
8uyGhpWwf5lrqXybStJTm1d4GUgH3ss/Pt8aZ2OjDWpRJ+ur1pGzGFpgOtGGoUV2
|
||||
2ZucrBn3sjQThux/tQdZ4R2IwSm+YExvBECWCh+Uvd9neK9CVoHQHD3uDug/0c9R
|
||||
9sRQW2vbOidNyffnZ9wXcUAW6V0ccz1cI6lP0Ent7Qx691wn9kUr5ixvembfxUyH
|
||||
jQuT79ngmEQq3aJ2Ol+pP0/9
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpgIBAAKCAQEAuT9FVVxTsOLjHATdjb+krJlsNAG9nlhnLgthPpaxa0Z0oVO0
|
||||
E0lRIkONCVWr6DvlfmZt/ncQM/lUomSs53y/fbo06VdNRV0TJRwcZQHvGtjigWCj
|
||||
AbTR+K5oNZFFWs4rTWOtbZyZne3OqkfD33y47eDAsaIT8IvzGNx1ZGX/Nfdapjeh
|
||||
XOZ9LFMh28xUBv5+JT+uVdSn3M1qZh7m8bw/1e82TyV/um+AE1JvelaVChTsDjUc
|
||||
ubSCrL7Jq4S8ar+dttXJdDtUBXtfHCgcS7bBptILiJN8wcLHaxV3w/da8G4EN/ng
|
||||
ifBJbzs1Qm+3DMhGqUpw7WXWrbFa9YV41Q9zZwIDAQABAoIBAQCgvkpHe8oTX416
|
||||
rq4hZf5a1vaRWkFTuZou1ikXymNBlu11X9COO7xvYvZq9zAoYHEPcYpYmLAyqVPL
|
||||
Zliytgjj7EQlhl/CpLUMKoxpCXiVb0V8xoIr5N+eTpiWguwPk373tFq1FoImDEic
|
||||
cZGByBQgNjp+6QksXgQfuo0TBX6jL/m/6EDNoONtiPsHqZkRaADqoYiPE0kfyRaO
|
||||
GmptOae0R8Y0Z4SkKnRqiokUzTIkjhf5QXYO0AkPXSkNgGS0Kf/JVnxyxfMMiCkF
|
||||
sQHXoEeqMevnmuny6S0oXQkp+UbJBtCH+bZlQ4d9PWdRd8UZUDBdeyEu/NRun5qj
|
||||
BS7zBRXBAoGBAOWNqkjYhq6lro5uu3pYkT2yFBQ9vQ0bXCRGuvG7fkqcH5+zgH4+
|
||||
WiqQuPVlNAG7Gg1D4XR1F5tIjPIs9qlY7G31aGOqYFdzWkEqQ6+wUXrM12rJAZut
|
||||
Pfu/aheuEH0tMiwNvQt9GUl0CFY8HtKhG61HZRXxaotxOc48GqbP9OOvAoGBAM6W
|
||||
3AgOGWVpEv1o+bn+g+38WgbQtvZOMLERSXMiPH7FBbkXAAZGoDLJ9uWaX602T1Gj
|
||||
sjaOFqWrgkaC2h/erItpht5x9FBO80PgYXbZlLWZWJzsjkC9tnm7yyHSueZ8R8/Q
|
||||
vBMD+NAdv9eqQJWw2Y3ZxKlSUHMkLQhdJvZtqwHJAoGBAOFywdQrfBMYu5g9nrkp
|
||||
NPQf6mJ6xCqUPWmPYdk56G4EaXaih8b1G/8EBfNUwsAUbyCqE0oaGeYzWeIbUOG/
|
||||
aO0RgcWotlgM/Y5UoQdypoNxnPvOkFrBycdvFhZNqPoXolfr4kffRC+E2w8+mpMJ
|
||||
EbKcFOZ5JMfwmvI2y4IbaYsXAoGBAIx25oRTkdDx8Id8qM9dzjYyLsQThVNTNqgu
|
||||
KNKvpJJNQ+blTI731lSyHb1fiU4sbyIDO1j8o0lho+JtdgHVVVw1FA6LTKKOC7lL
|
||||
BvnYVtRiv21zKgW6+CctGKCWtu+P8QPL2RTUzogysg3hJKii5kkcmCrIXQrsvfHB
|
||||
5IwJZQyBAoGBAND4BL5oABu7ygLIUxJVxrvJlr5Uk4CUa6I5MPJu6Yb+RPbQW5kX
|
||||
JEe5nl/OVyC/mc0yMZwPkudkYNHGNeaKwsjcQMNGHav6jnJoHHcdDmnXkO23xGYC
|
||||
TTdKoXlCkC0NeFzpLAI0x5zwgd+1wKFfc4ZCCvwQAjx4AUKX+kYPN6hI
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIESDCCAjACCQD0kF4yo85tSTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDExNTAwMDUx
|
||||
OFoXDTMwMDExMjAwMDUxOFowbzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEoMCYGA1UE
|
||||
AwwfKi5rdWJld2ViZGlhbGluLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBALX/q3xPMpTD9ewp87HtRs0XAOd4qcHIch75UMWb
|
||||
eaW8nqd4xL5YTfe89yVDbdq4FHqqQ1rivcwp/WSHbNvRyvDMNlXZTS8PS6RqL75B
|
||||
LljvzzrcIHax5WrUtrVUuFrlPN5yZW8fWB84ZY9EsX8UHB79rJdaS5r8B48/Ws/X
|
||||
BIxiNQyIC9pNIfEDRQCjbn4GRCvCaf91tBxVwQGA38PF5JRSxblEx+Cte5d3ODH6
|
||||
5gCKMBVCsMn84gr/WGamZannth8/Lrasduq5Pvj/cJ2h4PUoh1oKwpSsXAG9d2tY
|
||||
7AluVOVWvqJbvKKB1yegtZi77+D7oQ5ee3EOXriz+LWFsXMCAwEAATANBgkqhkiG
|
||||
9w0BAQsFAAOCAgEAm4oPL/mJAolyewL/jdbMWZT22oRKIYqxJQoHuTzeTQQInAUp
|
||||
KbTUuRKgbSz0HeoRESrxV14BI3XrVJlbctkyBRpi14bQPd4TzdBxDY+Rh9bkuaHw
|
||||
4zc8/mMYOT2xpq885BMTkd8YE98t3fyrrUYTBMCstBNMamcuV9hzA9RTuvtggUyT
|
||||
3E6lgGLaHyFQUp7z++zDiNDrEhILC698zC2EYbqM50PqqB2kcfMRLmYKv4yRgQPZ
|
||||
boSX15mc7ZBtU4Mb3bNPFR50PKbfrCi7KDIQiFse6TQONu7Pi3sN9GHVLfPhf7Nh
|
||||
acJkweVgP2zZUObcW1BtrI+yvgGMh4rbXGzoIerBRQgC64eH/I0OVZBSy2EiJDna
|
||||
T9tAczjvYAgR5qrXV33xY6DW6nPdUE0N5JgdHFoFn5uElEMiOyAWbAEvsQ6WtQCi
|
||||
f689rh4CwU1XQ+pEQBtoj9vy3ioeTvDzSj8js/ofdzIMC5xLQdwyFUcGbx3ntwrn
|
||||
4pQuny4A1rrK4pL8RQX7gvsXpuC+rlbew2IpbZ7CP6DJ8xbmktJtmfL0VsYiZjNr
|
||||
zpL/YSAazr+NZYCpYguBrL9aIzU38QC7hIWvN5s22Mx0r6RsOP3jAFkZy9TFOJaO
|
||||
HYfszg8SI1iG3jfB18TMLTcFDjVefM8rIsYiQ6ZPQQnP3uPht70Tz2vUHFI=
|
||||
-----END CERTIFICATE-----
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICtDCCAZwCAQAwbzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFUmFmYXkxDDAKBgNVBAsMA0RldjEoMCYGA1UEAwwfKi5r
|
||||
dWJld2ViZGlhbGluLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBALX/q3xPMpTD9ewp87HtRs0XAOd4qcHIch75UMWbeaW8nqd4
|
||||
xL5YTfe89yVDbdq4FHqqQ1rivcwp/WSHbNvRyvDMNlXZTS8PS6RqL75BLljvzzrc
|
||||
IHax5WrUtrVUuFrlPN5yZW8fWB84ZY9EsX8UHB79rJdaS5r8B48/Ws/XBIxiNQyI
|
||||
C9pNIfEDRQCjbn4GRCvCaf91tBxVwQGA38PF5JRSxblEx+Cte5d3ODH65gCKMBVC
|
||||
sMn84gr/WGamZannth8/Lrasduq5Pvj/cJ2h4PUoh1oKwpSsXAG9d2tY7AluVOVW
|
||||
vqJbvKKB1yegtZi77+D7oQ5ee3EOXriz+LWFsXMCAwEAAaAAMA0GCSqGSIb3DQEB
|
||||
CwUAA4IBAQBogrS+PnokRvp1rFYiYAEg4PPaIq6EYoPbRQS88ms0+MEjblXWW2EE
|
||||
CnsXL/eFCQqi08HQCMzVAkAS9jqF0ZQ5X2tvVQB3OVddAOvlFBSFGhakoSDPuqZN
|
||||
btQMfH//GRubwBftHbu66qKsltutHnobIts0LiIWxFsK0gNUOQDAU7ts44EDY5yq
|
||||
iUR2slS077+jGFI4GvB2vmdNTX8JupOMH+60wpZIDSIwI919ANPTj3vBxdVmITP2
|
||||
V8wFtKl12Lznww2u8OcAH6g0v74FH+FfCZIVcJWBrinuWCmrw0VdG+s+D9/2PnkN
|
||||
6XAarzL3eYilbin/aBE6NafdERkSCTat
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAtf+rfE8ylMP17Cnzse1GzRcA53ipwchyHvlQxZt5pbyep3jE
|
||||
vlhN97z3JUNt2rgUeqpDWuK9zCn9ZIds29HK8Mw2VdlNLw9LpGovvkEuWO/POtwg
|
||||
drHlatS2tVS4WuU83nJlbx9YHzhlj0SxfxQcHv2sl1pLmvwHjz9az9cEjGI1DIgL
|
||||
2k0h8QNFAKNufgZEK8Jp/3W0HFXBAYDfw8XklFLFuUTH4K17l3c4MfrmAIowFUKw
|
||||
yfziCv9YZqZlqee2Hz8utqx26rk++P9wnaHg9SiHWgrClKxcAb13a1jsCW5U5Va+
|
||||
olu8ooHXJ6C1mLvv4PuhDl57cQ5euLP4tYWxcwIDAQABAoIBAGs88vaUU+GEdetp
|
||||
7MXyYb2GyGmbl6svSM8naIiHS+50baeQaZ0euxI2rgmu6ZPu02JT4Mw0vlEGjOAn
|
||||
S+VagJHSQlHjcK9B+/gs+WTJU13kL98mxZoqyFtiayX9fYNRf8Qy88G+XlZHDNCW
|
||||
UV/noYpBPukPs2znBC1Lz16X+34bgBn1kydD5XrRi1WujYQV+Bd+qbyd5xfo3ICA
|
||||
7aLo1mZF5ZRSYXz044w4E8pLzi3SfdvHBGqIHqhu1I7g/aumb//QbPUGinVi0lJp
|
||||
Gne0fMSWC19Ueg3XUv2YgTOKRZ0teQ4gNTqJZU2omU+tNkQOL8Lem9EXgUr3ULmd
|
||||
BEeWlgECgYEA72NahW69StWIQrxUB08ePKmYZhtpi7NlGsuMPVsJwIjn50LnmkPx
|
||||
tb54OROqGYYPKeWj1LDaL8/WKSzU6Xi2JC5c4K7w4GsHP0Fibk7qMs4PI8gHNYUW
|
||||
OR6SpbkHSj+XaO4Y5ZYxweEddjLmzBl1cU5xQFwE6B4v7QmjssoWcSECgYEAwqDQ
|
||||
TwT/m0rY5KAZ7C1ziWhzTSnYDYkh8UyeW9jcbjGFafuWk5pbkGGJhiE8N899wfEB
|
||||
xM44U5zryjWXfNnRVyL/0E0UUaIiEFXmbh9PpiMn67qIm0/bE4cTR5EK+1Cv5lH5
|
||||
40PcIAuaHCrwExF2n/o8G1Qw1CtM/2Mh5QwVzBMCgYEAvaj2p+6ztF13JoB1BpFt
|
||||
gFxRrNwdBByuhssrodTF5i/Ro8zDF9qq3vY34+irhKtMykHxSeqQAv9kSp0FVrBX
|
||||
hlThKvYPS44gYMJZzNFjBbtyDURGSeXWVIzfXMM6fl3hhLXXLdaQN242XFY5uwyU
|
||||
mp+uZHJDRO/dwqw3cMhhfWECgYEAwcdhf7uHTzOnXYI2LRtX1HCllCdcUKW/oMNb
|
||||
TDFPz3sIzWvMESv3jHpAdcZzcVHqcQWncC6ukDlF3m+bY5hvQKW9M8T6vQiDh+Yu
|
||||
5mfQYqbQIXj4eEJ66idrv66e03gTmmr2NRukeFd02iS6IRIbHM8Ft2QMtcJjCEfI
|
||||
QIfWz/cCgYEAw/zG/jKrkrk+TSgy6UuMgzFd9I2p8Fi8yl7QZFG2nB7uRtH80FFc
|
||||
LyvsdfDDV+8NWUNgnKreBFWR5I9oI3vB74PMp27YrBV4L11ne1L5FXKGry5G2D1M
|
||||
2GgkZSe34gTsmtM1tFF7mBNEs/DfMxURb0jsPw/9zC8ztqA+3QvV7jw=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIETzCCAjcCCQD0kF4yo85tUjANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDQwNzA3MjYy
|
||||
N1oXDTMwMDQwNTA3MjYyN1owdjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFcmFmYXkxFDASBgNVBAsMC2VuZ2luZWVyaW5n
|
||||
MScwJQYDVQQDDB4qLmt1YmVjdGwucGVlci5yZWxheS5yYWZheS5kZXYwggEiMA0G
|
||||
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAx45z7f2bXFjh0yPRaPqmiJWhRXDf
|
||||
Q5JiyUlZlBfon12mmMx8C/1RY5NROd7xGN2Fokys7yNLq/PFl0NzoQDseJNO6aTg
|
||||
wO1gi7MB3roiDFe1FRevsSapwu0ngOPovSShiFKsZOaXUeNoDT1d+eCZd9cu2Pwi
|
||||
FhxCiblju6EckXKAPJGzD2SknLM8P5ky+n1+5801ebNoobP5E2/XSyaiyNSzqoIs
|
||||
LkPgdYU9PpBH3CS0YDBSRgmjM1L3R0gO6Oy6KitgUEXXNQ4mCANcJX46bgfjt2iw
|
||||
fjiiywJjLkRgBkhHUtzFPe19mma1P96a9XRKlrWtyCLWr0TRCxzftwjzAgMBAAEw
|
||||
DQYJKoZIhvcNAQELBQADggIBAKc7sPjByTWLp/zPU1ALe0vRa1iytnPy1rdUdSeX
|
||||
kEivS7ktsmPstD8c1jq9MmmkTQaOMTD4jbyd3YFPyhIH8NynI5OtADTdRTH7N2+M
|
||||
bkDzW+zuGhxReErS7FsDJ30L3H8Ry2Ep2ZBCUD69KglEk7sJLKt5iQtyVAiuoH4Y
|
||||
qn9xwGXdyAT1NiibepYSr5NNDeOanbeXTFZsGbDgYdE4QdWbIdlaj8aqmY2cw2LW
|
||||
cflLjTZw0sIILGhJywjVjF29gb/1HykV8/UVYg344moKjjRaYUPFwFR2R/1vGfEB
|
||||
O4aNM6e/AeBhY5WZIIxCFGQiG9o6QomzEFryD3sbx4V+qiDN3xd5AJEbpTvxOCts
|
||||
3dUeacxmlaYfDPvJb3qR17sPgjot6Wxz8EcsHxqO/AvcBpcAZbLRsMszv78JICpT
|
||||
FYnBJreOL6C9I7MjhQRS6DAhOExrCqgYaWxf8vDUXkY/Y0TFERwNsOhO5uIRPmBL
|
||||
VroyQkamWvEfkobGRe9RL9pi5kxPp6VxColl7T/C53XTCku7il2avER/yTMG+ceB
|
||||
E+htQLuPBkZt2vaDsvHaFgageFgmUYTps92Ku6cjBX1UYpAuaRIKRwCHLDd3PM27
|
||||
QwgrBIKx2LOuMlLpKF/D3emGqZHty4bWJTpXURMUofviZ6mi2kFaqTcySWCzCEuP
|
||||
9maR
|
||||
-----END CERTIFICATE-----
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICuzCCAaMCAQAwdjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFcmFmYXkxFDASBgNVBAsMC2VuZ2luZWVyaW5nMScwJQYD
|
||||
VQQDDB4qLmt1YmVjdGwucGVlci5yZWxheS5yYWZheS5kZXYwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDAx45z7f2bXFjh0yPRaPqmiJWhRXDfQ5JiyUlZ
|
||||
lBfon12mmMx8C/1RY5NROd7xGN2Fokys7yNLq/PFl0NzoQDseJNO6aTgwO1gi7MB
|
||||
3roiDFe1FRevsSapwu0ngOPovSShiFKsZOaXUeNoDT1d+eCZd9cu2PwiFhxCiblj
|
||||
u6EckXKAPJGzD2SknLM8P5ky+n1+5801ebNoobP5E2/XSyaiyNSzqoIsLkPgdYU9
|
||||
PpBH3CS0YDBSRgmjM1L3R0gO6Oy6KitgUEXXNQ4mCANcJX46bgfjt2iwfjiiywJj
|
||||
LkRgBkhHUtzFPe19mma1P96a9XRKlrWtyCLWr0TRCxzftwjzAgMBAAGgADANBgkq
|
||||
hkiG9w0BAQsFAAOCAQEAimAaHYatwlCfq0OtI3tkASb+KkJxk49INZTswzQvyjvr
|
||||
6mMFVplX+1fQGAYkZGJSjxwdAt2HnlgEyUybZHFFoBgnc/EQWlXfdY6kWIos5bgD
|
||||
j3PyEEIQ0tCDnXQrABWZ7FSY7WRzEXmSQQwBznq5bprSKM0k5XBxXRo130xV7zCZ
|
||||
fm2BTIl4hHc9hCc/UWQ6Z6R+pniiZQEaekZ6SpGjxdss5QaWMcvaDhtHSZi0wmRP
|
||||
X+SyPsY6v3wv6Xp7cnMRsetthmm0iwy/Ctzk6Stl0KTFPqXoAttR/Oi5ynNT7CgY
|
||||
KrTFCNr3UCY1xdr8vLYV+6RyIU9NdlgwnYrBiBU6gg==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAwMeOc+39m1xY4dMj0Wj6poiVoUVw30OSYslJWZQX6J9dppjM
|
||||
fAv9UWOTUTne8RjdhaJMrO8jS6vzxZdDc6EA7HiTTumk4MDtYIuzAd66IgxXtRUX
|
||||
r7EmqcLtJ4Dj6L0koYhSrGTml1HjaA09XfngmXfXLtj8IhYcQom5Y7uhHJFygDyR
|
||||
sw9kpJyzPD+ZMvp9fufNNXmzaKGz+RNv10smosjUs6qCLC5D4HWFPT6QR9wktGAw
|
||||
UkYJozNS90dIDujsuiorYFBF1zUOJggDXCV+Om4H47dosH44ossCYy5EYAZIR1Lc
|
||||
xT3tfZpmtT/emvV0Spa1rcgi1q9E0Qsc37cI8wIDAQABAoIBAQC3M63r/Aqbv1n0
|
||||
WdvbIYG6C2jvVveaJTQTTyi2yWcjOXgdX25MoHQ/CXsxoOZ+htvWKFPnsGcBfcrv
|
||||
Rv3h/+rJzxhm0OFQeefcbUZTi5+lxccAHqhg3eBZShZoCTQNtNn/7HZswILm4PpU
|
||||
ouhjy5inH91N9wU9O3flv85/ugq1AtmL5jLp97qKyafWgy3nsQrPf5N+k59qCEXI
|
||||
+giCKg3wKVgsFZW7bm+dBR6pgSvjfMnu3Yp5bJKNRQ4s/0DRcQJ9rsVvcQn5mWGW
|
||||
NabBZgzb/nHNAEOFvzypinm96h4Ma4afLZhThvFKMpn5pc9+32rq5/nqbK3rg8sX
|
||||
uNOOWLPpAoGBAOecyPI7nWcibSXsNFHKrAVdH8r7G+hY7v79+xdPx3FpQfSrlTFC
|
||||
EBOmPBWTxk1Un80Wby8ObL2oqNcbg37Y78OzmEswyNJkcz24OHY3IVF0uCtPJQVw
|
||||
JN2Z9cse/XOq/9RkSJzNtQOlSsezuDvid7tuWMmbGl6+OypNt+GOS1pfAoGBANUU
|
||||
A1PVoN8V18rWJEsKpJrUavUaVFTC4D0XeVyV4+6YydP+mw2KdLEO0+xBA0YTUIsM
|
||||
OLnY0FDPHby3XpjKoorBgGwm+CPbHVkUuqd5wuNn0b9ZdblFDFh0Ps+bzwEXs4d8
|
||||
isnPDOQaJuLlf20zTmIqnpZVGbZEb57oLaUhpgHtAoGAVcLlWWSfrQ+/ULp8yQh9
|
||||
1+KaoiOHOuqrXHoZHpGo7SKnjHx4Wuv2XgBA4VB9ria2oU88TjVOKJAqLLSAZVjY
|
||||
tyNqMfVXdyhAz8rGBWf2i13n0AmXUMMss22N6O+Js+nOnwufI4i8DSSIYxf2ER6T
|
||||
bTC36bbn9csEx25Nt1RkLIsCgYBUQAKEzm46Zw+ZAwz8ouus0Jqt6Ug474jsfvCc
|
||||
nCOwvrbm3MAAHaPAMoW234nk1lQ9doqjaUgM+6fda3+62DxmstYNbWcl/khfZaPb
|
||||
/ngBpJY5m6zBobyc6PHA8vFplC6HPsY9v2Fwe6qugmHdErFGfWWROXreJ7ce1Nzf
|
||||
cyuJjQKBgQCRFhYBHj2yTaDrZjFpP7ybyGejVS2xGQ3+r54YWh1+MA41A0As97Kd
|
||||
p1xK5KGxsdHOra6ApfsitGa8JjA7owFaMk+zrpCGyoRdoPAhyz/E9JksK8XW90s3
|
||||
zQffnMEuOoPp8GN51GlmsF2N5GpyMjUzuebrjTyYR1gX8qKTmERHaQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIESzCCAjMCCQD0kF4yo85tUTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDQwMzIzMTY0
|
||||
NFoXDTMwMDQwMTIzMTY0NFowcjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFUmFmYXkxFDASBgNVBAsMC0VuZ2luZWVyaW5n
|
||||
MSMwIQYDVQQDDBpzdGFyLnByb2JlLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAKVRchQ2YyJTBqoeXiGVgDBm2wxZVIqqOcLP
|
||||
TVVlRlgsIwboo1kfC1PNAUCcm5BSF1rqE9BZyKynYoOPlXRpI8LYNW+QMXyHg3/U
|
||||
8chBEuJNkU3tGdbwN3EkuThbWs/7VbKnw/3tS0bjBX858l2yqVWcgKqxH1xe9q4j
|
||||
f0RrC4+oZffwzSwkvjYTiVURW1Z/qT7VduwbkX6XzKc1JWLWOe5BJvlbZHZ13RWN
|
||||
vm0lMGdwzAtoIS7lKF0p12kD+kp1EeW+Sz2fYC4jHQq/i8chol+2PrOTe7MUQvO1
|
||||
mlJdfbcK7HABU3oDAc3xl6LTRAVPzThHJKoJCj+drXDRrJzECaUCAwEAATANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEAmhwJ/5fEYevog5AXzFpINkZGxSTSsH9nMMPEjNNDNpfh
|
||||
AliVNS+LVYISNe6w0vCJCNm2v6C/z/W3XlQ2leCXZd7aChWIVBoLjbg68sNbMyYA
|
||||
QFSERXkX0sPTskmsz7i26nX/j0BgoJ8WFTwfpc+6JA9QjanTnT/uaCGdoSvdHotJ
|
||||
1PzfzP/WnY1yq/YS73fRjf8rSaSv8qR1GbdRk2GXABXXwxjSLv3fQK7TzF+Pf7/w
|
||||
dnzKCNw/4XWyF6PhnDOyRFHrKyqWp6YMctk52WYUpYg0o+zDSG7si7pNW+NJxkde
|
||||
mnnLvWrgX5BMfSRnY3d0siQdyaGr2447z2Nr5gMNnsWv5NS43KrM+MXFFUUKMwuN
|
||||
lGE9Y4mScVb9rxouYZ2HCqnL8vi3dK9oq5jMTjF/ytEF4ACprd6WRRlPLX4rR4sp
|
||||
IXYyCGLRnCRBeMdKa5YDr08YsL3rOCWAc5EByALi/WQgFxr1qctqrylFhH88+eSB
|
||||
7KfLVl4Ji4ti2ETqwzqtQ2kfcemNgWBwxodnqXpVF197aCiZ3gnjT5t93FSLXRXx
|
||||
7JubuFzAeIOI/ICo2OiRZ2Gw+ANKSVtWnYODV/RiM/gRDYbv0jCHxA3PCbGJWTd1
|
||||
twx1oSo87N8gdC7NRL49bjtc6PRfPwow4/MUDLD0thjh29NaG7DiZf+1IsdGFvo=
|
||||
-----END CERTIFICATE-----
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICtzCCAZ8CAQAwcjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFUmFmYXkxFDASBgNVBAsMC0VuZ2luZWVyaW5nMSMwIQYD
|
||||
VQQDDBpzdGFyLnByb2JlLnJlbGF5LnJhZmF5LmRldjCCASIwDQYJKoZIhvcNAQEB
|
||||
BQADggEPADCCAQoCggEBAKVRchQ2YyJTBqoeXiGVgDBm2wxZVIqqOcLPTVVlRlgs
|
||||
Iwboo1kfC1PNAUCcm5BSF1rqE9BZyKynYoOPlXRpI8LYNW+QMXyHg3/U8chBEuJN
|
||||
kU3tGdbwN3EkuThbWs/7VbKnw/3tS0bjBX858l2yqVWcgKqxH1xe9q4jf0RrC4+o
|
||||
ZffwzSwkvjYTiVURW1Z/qT7VduwbkX6XzKc1JWLWOe5BJvlbZHZ13RWNvm0lMGdw
|
||||
zAtoIS7lKF0p12kD+kp1EeW+Sz2fYC4jHQq/i8chol+2PrOTe7MUQvO1mlJdfbcK
|
||||
7HABU3oDAc3xl6LTRAVPzThHJKoJCj+drXDRrJzECaUCAwEAAaAAMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQB9o+RvCbgUengcfOU8yLPtUwu3vVx0/4flcJvkq4UaYXIo6BqS
|
||||
Jt97bzOYAc213YeAqzt2ldx50Ja/55CF/z5L0nwviKNk8MRyIlXy6TYPsWsfOG55
|
||||
LqOrZEUtAJA9CVrZDt097JWl+LWFKRnV3Y90GzsnS7SRNGrKKZxSbLArh+T8toz/
|
||||
zjfK1Q+Gz2TR6UOtc/0/kylon3SwGcJdyESAhQ/RrG10XGwSy30lT0Eyp92I9A/f
|
||||
z+QJJrNugFkRwpBDzbiLIWjeVJqY3FSnuAqdKPSmsW4jVlzQhcLGIo/tN96BGjt9
|
||||
NZZVW0lpRX1K/5vL3fk992zIngep4o3355EL
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEApVFyFDZjIlMGqh5eIZWAMGbbDFlUiqo5ws9NVWVGWCwjBuij
|
||||
WR8LU80BQJybkFIXWuoT0FnIrKdig4+VdGkjwtg1b5AxfIeDf9TxyEES4k2RTe0Z
|
||||
1vA3cSS5OFtaz/tVsqfD/e1LRuMFfznyXbKpVZyAqrEfXF72riN/RGsLj6hl9/DN
|
||||
LCS+NhOJVRFbVn+pPtV27BuRfpfMpzUlYtY57kEm+VtkdnXdFY2+bSUwZ3DMC2gh
|
||||
LuUoXSnXaQP6SnUR5b5LPZ9gLiMdCr+LxyGiX7Y+s5N7sxRC87WaUl19twrscAFT
|
||||
egMBzfGXotNEBU/NOEckqgkKP52tcNGsnMQJpQIDAQABAoIBAQCVaoxh6lolLsdK
|
||||
QJIxZm7q0DvQ6Hg5r+ruwPCTaypuDM5Hs0HYDe/t+M7V9/W+NgP33rKz0EJIkiy+
|
||||
3apmAZUZyNJbGAcyF0Tp56vzo6UOtq7KsK53Drv9XgSuBBuK+Q2WoHzK54ru8ccJ
|
||||
G3WL7CuSPhYosFe44/euolSnoNxdJJGrvO4jCs80BbkMrCqf0CHFLm+WdoCEDDY+
|
||||
2g0552tGPMOh7rTRP8myK+uphNZnKH6LJEW9DjfCqbAhAwonJXmQy3yGPd+cfxOw
|
||||
UtdMnw6gWGQrrX5AQnQPDr7Y38UIKG5hoLohLacPdo3cs9CPA69TD9107392NuHh
|
||||
OUGFzsNtAoGBANNE48HAKdLSlhhx+hC+TVoz4GTzrHIaBr+R+kEe+jq8BI9tUnX1
|
||||
mBdsVi1lss21TQBDxTcMd7kvDQQh/T83XUJxH0XvgDyVaeGIIAAcfhDo5FDT4b5b
|
||||
VxvfW9ZWn7g5X3qTO289WzuUhZja4l8TV8c4RTUDBUZvNMFIvqCtrhbjAoGBAMhR
|
||||
8Y2vN2dUNCZNVNRxLMzUroq3b7gZ2/G+AhjXY7RIGeEA62w19wMoX7AFB1ls5QET
|
||||
Lyt+Tqii3OV8qjPBLm2eg2XiRDr44zTDEtscKUCsP1qBPYPWHgXOo5WTh1MJyvds
|
||||
GsMVfJ50G0KtXNQlioxAtcty1h+ulcZg0yt4fbvXAoGBAJpVMdgAy8yxf2oeIOII
|
||||
UrN5QAwfIbM8pf9d4SWfPoaXgPFRmDKJlXBO+Oky6JpzPevalf/vwKnr4CNLvRdo
|
||||
F12JC6JoIhKfx3g0m8PZDJLHvrn4/miziv/We90o7IaEiuYdFgbeGH5+sdWG2GVB
|
||||
2Ra0WYIvUbQxWqVzwaXZGlqnAoGBAI6cj+x/nmDouIvAKDFqNSvKCkzlVRrrBgOv
|
||||
cwy+YtQZNJtULUaHkMhluOG2YsoOVWaTgtRjAprZ/4s9WmqoEGaoIAGruUmGoTKR
|
||||
4l2tSc0qE5xaQDIYgJ0/xIQbWI8MfLvy8YaLSIICRNoOU/UQmPdKpmIl6jz57NUj
|
||||
X5MmH9VXAoGAKNLUmkjdZL/1nM4jO27ayp7vNdQ7Jwlpta4LA+BODDnb5KM80EKb
|
||||
+hIpeBgwytKJItm/PvVValW69iGgUx5Q+gN0sdKk+AtUQ3AvVnZf+C3pmkLqYvRl
|
||||
ASCXe+3FkuQI6wu8s5E+K5BZa+eHtMr1MlVE3KZ+LQ6Z5XakNAD5seA=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIETzCCAjcCCQD0kF4yo85tUjANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExEzARBgNVBAcMClBsZWFzYW50b24xDjAMBgNVBAoMBVJh
|
||||
ZmF5MQwwCgYDVQQLDANEZXYxDjAMBgNVBAMMBVJhZmF5MB4XDTIwMDQwNzA3MjYy
|
||||
N1oXDTMwMDQwNTA3MjYyN1owdjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQsw
|
||||
CQYDVQQHDAJQTDEOMAwGA1UECgwFcmFmYXkxFDASBgNVBAsMC2VuZ2luZWVyaW5n
|
||||
MScwJQYDVQQDDB4qLmt1YmVjdGwucGVlci5yZWxheS5yYWZheS5kZXYwggEiMA0G
|
||||
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAx45z7f2bXFjh0yPRaPqmiJWhRXDf
|
||||
Q5JiyUlZlBfon12mmMx8C/1RY5NROd7xGN2Fokys7yNLq/PFl0NzoQDseJNO6aTg
|
||||
wO1gi7MB3roiDFe1FRevsSapwu0ngOPovSShiFKsZOaXUeNoDT1d+eCZd9cu2Pwi
|
||||
FhxCiblju6EckXKAPJGzD2SknLM8P5ky+n1+5801ebNoobP5E2/XSyaiyNSzqoIs
|
||||
LkPgdYU9PpBH3CS0YDBSRgmjM1L3R0gO6Oy6KitgUEXXNQ4mCANcJX46bgfjt2iw
|
||||
fjiiywJjLkRgBkhHUtzFPe19mma1P96a9XRKlrWtyCLWr0TRCxzftwjzAgMBAAEw
|
||||
DQYJKoZIhvcNAQELBQADggIBAKc7sPjByTWLp/zPU1ALe0vRa1iytnPy1rdUdSeX
|
||||
kEivS7ktsmPstD8c1jq9MmmkTQaOMTD4jbyd3YFPyhIH8NynI5OtADTdRTH7N2+M
|
||||
bkDzW+zuGhxReErS7FsDJ30L3H8Ry2Ep2ZBCUD69KglEk7sJLKt5iQtyVAiuoH4Y
|
||||
qn9xwGXdyAT1NiibepYSr5NNDeOanbeXTFZsGbDgYdE4QdWbIdlaj8aqmY2cw2LW
|
||||
cflLjTZw0sIILGhJywjVjF29gb/1HykV8/UVYg344moKjjRaYUPFwFR2R/1vGfEB
|
||||
O4aNM6e/AeBhY5WZIIxCFGQiG9o6QomzEFryD3sbx4V+qiDN3xd5AJEbpTvxOCts
|
||||
3dUeacxmlaYfDPvJb3qR17sPgjot6Wxz8EcsHxqO/AvcBpcAZbLRsMszv78JICpT
|
||||
FYnBJreOL6C9I7MjhQRS6DAhOExrCqgYaWxf8vDUXkY/Y0TFERwNsOhO5uIRPmBL
|
||||
VroyQkamWvEfkobGRe9RL9pi5kxPp6VxColl7T/C53XTCku7il2avER/yTMG+ceB
|
||||
E+htQLuPBkZt2vaDsvHaFgageFgmUYTps92Ku6cjBX1UYpAuaRIKRwCHLDd3PM27
|
||||
QwgrBIKx2LOuMlLpKF/D3emGqZHty4bWJTpXURMUofviZ6mi2kFaqTcySWCzCEuP
|
||||
9maR
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICuzCCAaMCAQAwdjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
|
||||
DAJQTDEOMAwGA1UECgwFcmFmYXkxFDASBgNVBAsMC2VuZ2luZWVyaW5nMScwJQYD
|
||||
VQQDDB4qLmt1YmVjdGwucGVlci5yZWxheS5yYWZheS5kZXYwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDAx45z7f2bXFjh0yPRaPqmiJWhRXDfQ5JiyUlZ
|
||||
lBfon12mmMx8C/1RY5NROd7xGN2Fokys7yNLq/PFl0NzoQDseJNO6aTgwO1gi7MB
|
||||
3roiDFe1FRevsSapwu0ngOPovSShiFKsZOaXUeNoDT1d+eCZd9cu2PwiFhxCiblj
|
||||
u6EckXKAPJGzD2SknLM8P5ky+n1+5801ebNoobP5E2/XSyaiyNSzqoIsLkPgdYU9
|
||||
PpBH3CS0YDBSRgmjM1L3R0gO6Oy6KitgUEXXNQ4mCANcJX46bgfjt2iwfjiiywJj
|
||||
LkRgBkhHUtzFPe19mma1P96a9XRKlrWtyCLWr0TRCxzftwjzAgMBAAGgADANBgkq
|
||||
hkiG9w0BAQsFAAOCAQEAimAaHYatwlCfq0OtI3tkASb+KkJxk49INZTswzQvyjvr
|
||||
6mMFVplX+1fQGAYkZGJSjxwdAt2HnlgEyUybZHFFoBgnc/EQWlXfdY6kWIos5bgD
|
||||
j3PyEEIQ0tCDnXQrABWZ7FSY7WRzEXmSQQwBznq5bprSKM0k5XBxXRo130xV7zCZ
|
||||
fm2BTIl4hHc9hCc/UWQ6Z6R+pniiZQEaekZ6SpGjxdss5QaWMcvaDhtHSZi0wmRP
|
||||
X+SyPsY6v3wv6Xp7cnMRsetthmm0iwy/Ctzk6Stl0KTFPqXoAttR/Oi5ynNT7CgY
|
||||
KrTFCNr3UCY1xdr8vLYV+6RyIU9NdlgwnYrBiBU6gg==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAwMeOc+39m1xY4dMj0Wj6poiVoUVw30OSYslJWZQX6J9dppjM
|
||||
fAv9UWOTUTne8RjdhaJMrO8jS6vzxZdDc6EA7HiTTumk4MDtYIuzAd66IgxXtRUX
|
||||
r7EmqcLtJ4Dj6L0koYhSrGTml1HjaA09XfngmXfXLtj8IhYcQom5Y7uhHJFygDyR
|
||||
sw9kpJyzPD+ZMvp9fufNNXmzaKGz+RNv10smosjUs6qCLC5D4HWFPT6QR9wktGAw
|
||||
UkYJozNS90dIDujsuiorYFBF1zUOJggDXCV+Om4H47dosH44ossCYy5EYAZIR1Lc
|
||||
xT3tfZpmtT/emvV0Spa1rcgi1q9E0Qsc37cI8wIDAQABAoIBAQC3M63r/Aqbv1n0
|
||||
WdvbIYG6C2jvVveaJTQTTyi2yWcjOXgdX25MoHQ/CXsxoOZ+htvWKFPnsGcBfcrv
|
||||
Rv3h/+rJzxhm0OFQeefcbUZTi5+lxccAHqhg3eBZShZoCTQNtNn/7HZswILm4PpU
|
||||
ouhjy5inH91N9wU9O3flv85/ugq1AtmL5jLp97qKyafWgy3nsQrPf5N+k59qCEXI
|
||||
+giCKg3wKVgsFZW7bm+dBR6pgSvjfMnu3Yp5bJKNRQ4s/0DRcQJ9rsVvcQn5mWGW
|
||||
NabBZgzb/nHNAEOFvzypinm96h4Ma4afLZhThvFKMpn5pc9+32rq5/nqbK3rg8sX
|
||||
uNOOWLPpAoGBAOecyPI7nWcibSXsNFHKrAVdH8r7G+hY7v79+xdPx3FpQfSrlTFC
|
||||
EBOmPBWTxk1Un80Wby8ObL2oqNcbg37Y78OzmEswyNJkcz24OHY3IVF0uCtPJQVw
|
||||
JN2Z9cse/XOq/9RkSJzNtQOlSsezuDvid7tuWMmbGl6+OypNt+GOS1pfAoGBANUU
|
||||
A1PVoN8V18rWJEsKpJrUavUaVFTC4D0XeVyV4+6YydP+mw2KdLEO0+xBA0YTUIsM
|
||||
OLnY0FDPHby3XpjKoorBgGwm+CPbHVkUuqd5wuNn0b9ZdblFDFh0Ps+bzwEXs4d8
|
||||
isnPDOQaJuLlf20zTmIqnpZVGbZEb57oLaUhpgHtAoGAVcLlWWSfrQ+/ULp8yQh9
|
||||
1+KaoiOHOuqrXHoZHpGo7SKnjHx4Wuv2XgBA4VB9ria2oU88TjVOKJAqLLSAZVjY
|
||||
tyNqMfVXdyhAz8rGBWf2i13n0AmXUMMss22N6O+Js+nOnwufI4i8DSSIYxf2ER6T
|
||||
bTC36bbn9csEx25Nt1RkLIsCgYBUQAKEzm46Zw+ZAwz8ouus0Jqt6Ug474jsfvCc
|
||||
nCOwvrbm3MAAHaPAMoW234nk1lQ9doqjaUgM+6fda3+62DxmstYNbWcl/khfZaPb
|
||||
/ngBpJY5m6zBobyc6PHA8vFplC6HPsY9v2Fwe6qugmHdErFGfWWROXreJ7ce1Nzf
|
||||
cyuJjQKBgQCRFhYBHj2yTaDrZjFpP7ybyGejVS2xGQ3+r54YWh1+MA41A0As97Kd
|
||||
p1xK5KGxsdHOra6ApfsitGa8JjA7owFaMk+zrpCGyoRdoPAhyz/E9JksK8XW90s3
|
||||
zQffnMEuOoPp8GN51GlmsF2N5GpyMjUzuebrjTyYR1gX8qKTmERHaQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
|
||||
dialouts:
|
||||
kubectl:
|
||||
proto: https
|
||||
addr: cluster1.kubectldialin.relay.rafay.dev:443
|
||||
relay_service_sni: cluster1.kubectl.relay.rafay.dev
|
||||
root_ca: testdata/certs/rootCA.crt
|
||||
client_crt: testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.crt
|
||||
client_key: testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.key
|
||||
#use this if address is not avaialable from environment variable
|
||||
upstream_addr: https://relay.rafay.dev:7443
|
||||
upstream_skip_verify: true
|
||||
upstream_client_crt: testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.crt
|
||||
upstream_client_key: testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.key
|
||||
upstream_rootCA: testdata/certs/rootCA.crt
|
||||
version: 1
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
|
||||
dialouts:
|
||||
kubectl:
|
||||
proto: https
|
||||
addr: cluster2.kubectldialin.relay.rafay.dev:443
|
||||
relay_service_sni: cluster1.kubectl.relay.rafay.dev
|
||||
root_ca: testdata/certs/rootCA.crt
|
||||
client_crt: testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.crt
|
||||
client_key: testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.key
|
||||
#use this if address is not avaialable from environment variable
|
||||
upstream_addr: https://relay.rafay.dev:7443
|
||||
upstream_skip_verify: true
|
||||
upstream_client_crt: testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.crt
|
||||
upstream_client_key: testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.key
|
||||
upstream_rootCA: testdata/certs/rootCA.crt
|
||||
version: 1
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 181 KiB |
@@ -0,0 +1,19 @@
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJWekNCL3FBREFnRUNBZ0VBTUFvR0NDcUdTTTQ5QkFNQ01DTXhJVEFmQmdOVkJBTU1HR3N6Y3kxelpYSjIKWlhJdFkyRkFNVFUzTnpneE1qZ3lOakFlRncweE9URXlNekV4TnpJd01qWmFGdzB5T1RFeU1qZ3hOekl3TWpaYQpNQ014SVRBZkJnTlZCQU1NR0dzemN5MXpaWEoyWlhJdFkyRkFNVFUzTnpneE1qZ3lOakJaTUJNR0J5cUdTTTQ5CkFnRUdDQ3FHU000OUF3RUhBMElBQkNicWNTcklQQ2p5amE3cTg2Zk04SDlkMHJuMGlnYmpZaTRKalQ4c1BobTEKNXVVbm5NZHdVTytlRUY4eVU3cEdEUm04S2FSSER2QWF5SU0rbmloTkFsK2pJekFoTUE0R0ExVWREd0VCL3dRRQpBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSVFEMCtNT2piSXdxCm1ES3YveVVlSkFXVTVSemp0d3hmSHFmSjUwRnIrckxoMmdJZ0JWSjdMYkRwWXZKNEJDT3B5V0puMlJpRTBwY1IKZ0xZaUF1YlJNcXoxYU1jPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
server: https://192.168.56.103:6443 # set to your cluser IP
|
||||
name: default
|
||||
contexts:
|
||||
- context:
|
||||
cluster: default
|
||||
user: default
|
||||
name: default
|
||||
current-context: default
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: default
|
||||
user:
|
||||
password: 15c80273fd3e8daae8a65ba86d8f6001
|
||||
username: admin
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNWakNDQWYyZ0F3SUJBZ0lSQVBmN1cwSVg5NUlsMVA2MXpmcHpVV2d3Q2dZSUtvWkl6ajBFQXdJd2dZb3gKRERBS0JnTlZCQVlUQTFWVFFURVRNQkVHQTFVRUNCTUtRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCeE1KVTNWdQpibmwyWVd4bE1Sb3dHQVlEVlFRS0V4RlNZV1poZVNCVGVYTjBaVzF6SUVsdVl6RVZNQk1HQTFVRUN4TU1VbUZtCllYa2dVMlZ1ZEhKNU1SNHdIQVlEVlFRREV4VnlZV1poZVMxamIzSmxMWEpsYkdGNUxYVnpaWEl3SGhjTk1qQXcKTkRJNE1ESXdOakEyV2hjTk16QXdOREk0TURJd05qQTJXakNCaWpFTU1Bb0dBMVVFQmhNRFZWTkJNUk13RVFZRApWUVFJRXdwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSEV3bFRkVzV1ZVhaaGJHVXhHakFZQmdOVkJBb1RFVkpoClptRjVJRk41YzNSbGJYTWdTVzVqTVJVd0V3WURWUVFMRXd4U1lXWmhlU0JUWlc1MGNua3hIakFjQmdOVkJBTVQKRlhKaFptRjVMV052Y21VdGNtVnNZWGt0ZFhObGNqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQQpCR0MzcHp4NkRNalpvRVowSXJLT1p5cHduSWlEcVhZbkRDc0NUSFBZNHZJS3lWSWU3N3JBUDdhYXBvZVZvNjJPCjN0WW1WS0NuSjdUUUpIZjQyc3pkejhXalFqQkFNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRUZqQVUKQmdnckJnRUZCUWNEQWdZSUt3WUJCUVVIQXdFd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBS0JnZ3Foa2pPUFFRRApBZ05IQURCRUFpQmE3ZSthKzlSeXhMaDllZnBOT1ErK0hDcHI1SC95d3QwWUFCUFNqV3ZjN0FJZ01kZ0ZaV0R2ClBIMUtZYjB5VUJwRmNPcEVnRFdsdVRXb1NvUU9EclJETzNjPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
server: https://4qkolkn.user.relay.rafay.local:10002
|
||||
#server: https://4qkolkn.user.relay.rafay.local:443
|
||||
name: c-5
|
||||
contexts:
|
||||
- context:
|
||||
cluster: c-5
|
||||
user: rafay-core-debug
|
||||
name: c-5
|
||||
current-context: c-5
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: rafay-core-debug
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ6RENDQVhHZ0F3SUJBZ0lRYWhJQW9CZzJVdkV2ZjR6OEZCZkwvVEFLQmdncWhrak9QUVFEQWpDQmlqRU0KTUFvR0ExVUVCaE1EVlZOQk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGhNUkl3RUFZRFZRUUhFd2xUZFc1dQplWFpoYkdVeEdqQVlCZ05WQkFvVEVWSmhabUY1SUZONWMzUmxiWE1nU1c1ak1SVXdFd1lEVlFRTEV3eFNZV1poCmVTQlRaVzUwY25reEhqQWNCZ05WQkFNVEZYSmhabUY1TFdOdmNtVXRjbVZzWVhrdGRYTmxjakFlRncweU1EQTAKTWpnd05qVXlOREphRncweU1EQTBNamt3TmpVeU5ESmFNQnN4R1RBWEJnTlZCQU1URUhKaFptRjVMV052Y21VdApaR1ZpZFdjd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFSemhBWWsyYnB1MnAvTzRwbE5iMmYyCm5PTFoxM2M5cXlEYnBiOGN6RGpsdVpINVdUR0FMNFRQem5RYkFxaUNTNzNFTU4zR1lkRXRqZ0tGZFkzRGp4aWMKb3ljd0pUQU9CZ05WSFE4QkFmOEVCQU1DQmFBd0V3WURWUjBsQkF3d0NnWUlLd1lCQlFVSEF3SXdDZ1lJS29aSQp6ajBFQXdJRFNRQXdSZ0loQUplbWY2WHFpRDdQV3BuOWNqNVBMVTFJRUQ1VDg2ZFZPWDMyU1dyQXRqazlBaUVBCmkyQWl3Qkk4ZUxRejdWNGF6YVBLLzZwbkZ2c29hWlRINEhZY0JPMnhDOFk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSVB5Q3IzcjJJdkRMREFiUjR1ajdPbVg3bnJtczlSZ0V3TXptRDQyaU1GY0tvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFYzRRR0pObTZidHFmenVLWlRXOW45cHppMmRkM1Bhc2cyNlcvSE13NDVibVIrVmt4Z0MrRQp6ODUwR3dLb2drdTl4RERkeG1IUkxZNENoWFdOdzQ4WW5BPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- name: default-cluster
|
||||
cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJWekNCL3FBREFnRUNBZ0VBTUFvR0NDcUdTTTQ5QkFNQ01DTXhJVEFmQmdOVkJBTU1HR3N6Y3kxelpYSjIKWlhJdFkyRkFNVFUzTnpneE1qZ3lOakFlRncweE9URXlNekV4TnpJd01qWmFGdzB5T1RFeU1qZ3hOekl3TWpaYQpNQ014SVRBZkJnTlZCQU1NR0dzemN5MXpaWEoyWlhJdFkyRkFNVFUzTnpneE1qZ3lOakJaTUJNR0J5cUdTTTQ5CkFnRUdDQ3FHU000OUF3RUhBMElBQkNicWNTcklQQ2p5amE3cTg2Zk04SDlkMHJuMGlnYmpZaTRKalQ4c1BobTEKNXVVbm5NZHdVTytlRUY4eVU3cEdEUm04S2FSSER2QWF5SU0rbmloTkFsK2pJekFoTUE0R0ExVWREd0VCL3dRRQpBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSVFEMCtNT2piSXdxCm1ES3YveVVlSkFXVTVSemp0d3hmSHFmSjUwRnIrckxoMmdJZ0JWSjdMYkRwWXZKNEJDT3B5V0puMlJpRTBwY1IKZ0xZaUF1YlJNcXoxYU1jPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
server: https://192.168.56.103:6443
|
||||
contexts:
|
||||
- name: default-context
|
||||
context:
|
||||
cluster: default-cluster
|
||||
namespace: default
|
||||
user: default-user
|
||||
current-context: default-context
|
||||
users:
|
||||
- name: default-user
|
||||
user:
|
||||
token: eyJhbGciOiJSUzI1NiIsImtpZCI6InBYSV8yNW81MXpaTnN4WGNwcGNYdHoxUUFxeklHenZBRmhyRTAyU211ZHMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Im5hbWVzcGFjZS1hZG1pbi1zYS10b2tlbi14ajdubSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJuYW1lc3BhY2UtYWRtaW4tc2EiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJjMjNlODc1Yi1kM2EzLTQ2YjEtOThlOS03YjkzODc0MGRkOTAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpuYW1lc3BhY2UtYWRtaW4tc2EifQ.EdgMATO61V4katN3heaKdhPbyVd0vqc6FhG9ULmwZeXcQqgfZbnDIoOHbkCIPLCoL3CDfci-0JpiVmtG4_N3qxxZcyySsaHnWnyzaYEW0_FNjmtvKW13nwwM0t29iKu_AAaF-qk1dgJwvnQCR_2-nUb1NSjf_Hly25DkstHrsKfDlZM-fYR9HDlMdRXJ8xVX9YiMkAlOifgjqcQpzheoOxRd_yjGUmZVJUHBrjcT-1OdBmvhDjMU48dfdxadWQoymDaGMUbRsNKtPdrfMSrO_HBma5B_7HVJ2PbwQLice7ENltuue6cqR0GiYCKmMrBwDk6m1YweSZvaQIw5jv166A
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- name: default-cluster
|
||||
cluster:
|
||||
server: https://123abcd.user.relay.rafay.local:443
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNWakNDQWYyZ0F3SUJBZ0lSQU5yYkV6ZDlsYm4yc0xXb3J1ZEMyZWN3Q2dZSUtvWkl6ajBFQXdJd2dZb3gKRERBS0JnTlZCQVlUQTFWVFFURVRNQkVHQTFVRUNCTUtRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCeE1KVTNWdQpibmwyWVd4bE1Sb3dHQVlEVlFRS0V4RlNZV1poZVNCVGVYTjBaVzF6SUVsdVl6RVZNQk1HQTFVRUN4TU1VbUZtCllYa2dVMlZ1ZEhKNU1SNHdIQVlEVlFRREV4VnlZV1poZVMxamIzSmxMWEpsYkdGNUxYVnpaWEl3SGhjTk1qQXcKTkRJeU1EYzFOakkxV2hjTk16QXdOREl5TURjMU5qSTFXakNCaWpFTU1Bb0dBMVVFQmhNRFZWTkJNUk13RVFZRApWUVFJRXdwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSEV3bFRkVzV1ZVhaaGJHVXhHakFZQmdOVkJBb1RFVkpoClptRjVJRk41YzNSbGJYTWdTVzVqTVJVd0V3WURWUVFMRXd4U1lXWmhlU0JUWlc1MGNua3hIakFjQmdOVkJBTVQKRlhKaFptRjVMV052Y21VdGNtVnNZWGt0ZFhObGNqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQQpCQnBYL2prbW5sNml2RzVrbndrcE1qa24vYmxuWk5tVjlLQTN6R00rTTZKOE5EVUNPT294QURSUmRIZFZOajltCjdTY0pKdlpJczczMk5kbjVreXFndEJlalFqQkFNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRUZqQVUKQmdnckJnRUZCUWNEQWdZSUt3WUJCUVVIQXdFd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBS0JnZ3Foa2pPUFFRRApBZ05IQURCRUFpQkZhWHNtaWlicFpWVzNLZ3RvRm5OODdhQWZuaFZETXgvUmpSeDEzQjJNMEFJZ0FhTzZFUFMvClk4azZMSVhIMWVEMmxOdEsrVi9pMHhFQndEVVA3L0tyV2Y0PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
contexts:
|
||||
- name: default-context
|
||||
context:
|
||||
cluster: default-cluster
|
||||
namespace: default
|
||||
user: default-user
|
||||
current-context: default-context
|
||||
users:
|
||||
- name: default-user
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUIyRENDQVg2Z0F3SUJBZ0lSQUxFR01TQUErajFLRCtuNllibUdrUW93Q2dZSUtvWkl6ajBFQXdJd2dZb3gKRERBS0JnTlZCQVlUQTFWVFFURVRNQkVHQTFVRUNCTUtRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCeE1KVTNWdQpibmwyWVd4bE1Sb3dHQVlEVlFRS0V4RlNZV1poZVNCVGVYTjBaVzF6SUVsdVl6RVZNQk1HQTFVRUN4TU1VbUZtCllYa2dVMlZ1ZEhKNU1SNHdIQVlEVlFRREV4VnlZV1poZVMxamIzSmxMWEpsYkdGNUxYVnpaWEl3SGhjTk1qQXcKTkRJME1ETXlPREExV2hjTk16QXdOREkwTURNeU9EQTFXakE4TVIwd0d3WURWUVFMRXhSaWNXWjJhR0ZpYVhCMApNMkV5WnpRMk9UZzNaekViTUJrR0ExVUVBeE1TYm1GdFpYTndZV05sTFdGa2JXbHVMWE5oTUZrd0V3WUhLb1pJCnpqMENBUVlJS29aSXpqMERBUWNEUWdBRU5lWGhyNTh3dzlRam5mSHRyd29yNlB3MlM3R0NrZ0plMlpMSm43bGUKSUxMVkVJcVVzUGVnY0Jvdzd3Q005ZTcrSjR5M1RpOEREa0U4R2NVcXU0UmVHS01TTUJBd0RnWURWUjBQQVFILwpCQVFEQWdXZ01Bb0dDQ3FHU000OUJBTUNBMGdBTUVVQ0lRRGVCTmQvcXV2SVprN3pib3Jsb1dPTldkRVA3eDlCCjQ5eEhWMStISzU2ZHN3SWdmTXVVSFA2MVdJS1F5c1ZKdjFkbU1CeDUwdEUzRWJIU3piVlZJdURscTlnPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUhRYVBBVGZUZW1uNzZ5bEg3TCs5d1VmTlFVYUljQWE4eERndmZyMnhKOTBvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFTmVYaHI1OHd3OVFqbmZIdHJ3b3I2UHcyUzdHQ2tnSmUyWkxKbjdsZUlMTFZFSXFVc1BlZwpjQm93N3dDTTllNytKNHkzVGk4RERrRThHY1VxdTRSZUdBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- name: default-cluster
|
||||
cluster:
|
||||
server: https://123abcd.user.relay.rafay.local:443
|
||||
certificate-authority: /var/relayuserroot.crt
|
||||
# server: https://cluster1.kubectl.relay.rafay.dev:443
|
||||
# certificate-authority: /Users/stephanbenny/code/src/github.com/RafaySystems/rafay-relay/testdata/certs/rootCA.crt
|
||||
contexts:
|
||||
- name: default-context
|
||||
context:
|
||||
cluster: default-cluster
|
||||
namespace: default
|
||||
user: default-user
|
||||
current-context: default-context
|
||||
users:
|
||||
- name: default-user
|
||||
user:
|
||||
client-certificate: /var/relayuser.crt
|
||||
client-key: /var/relayuser.key
|
||||
# client-certificate: /Users/stephanbenny/code/src/github.com/RafaySystems/rafay-relay/testdata/certs/clientcerts/star.namespace-admin-sa.crt
|
||||
# client-key: /Users/stephanbenny/code/src/github.com/RafaySystems/rafay-relay/testdata/certs/clientcerts/star.namespace-admin-sa.key
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://cluster2.kubectl.relay.rafay.dev:443
|
||||
certificate-authority: /Users/stephanbenny/code/src/github.com/RafaySystems/rafay-relay/testdata/certs/rootCA.crt
|
||||
name: default
|
||||
contexts:
|
||||
- context:
|
||||
cluster: default
|
||||
user: namespace-admin-sa
|
||||
name: default
|
||||
current-context: default
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: namespace-admin-sa
|
||||
user:
|
||||
client-certificate: /Users/stephanbenny/code/src/github.com/RafaySystems/rafay-relay/testdata/certs/clientcerts/star.namespace-admin-sa.crt
|
||||
client-key: /Users/stephanbenny/code/src/github.com/RafaySystems/rafay-relay/testdata/certs/clientcerts/star.namespace-admin-sa.key
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
#certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJWekNCL3FBREFnRUNBZ0VBTUFvR0NDcUdTTTQ5QkFNQ01DTXhJVEFmQmdOVkJBTU1HR3N6Y3kxelpYSjIKWlhJdFkyRkFNVFUzTnpneE1qZ3lOakFlRncweE9URXlNekV4TnpJd01qWmFGdzB5T1RFeU1qZ3hOekl3TWpaYQpNQ014SVRBZkJnTlZCQU1NR0dzemN5MXpaWEoyWlhJdFkyRkFNVFUzTnpneE1qZ3lOakJaTUJNR0J5cUdTTTQ5CkFnRUdDQ3FHU000OUF3RUhBMElBQkNicWNTcklQQ2p5amE3cTg2Zk04SDlkMHJuMGlnYmpZaTRKalQ4c1BobTEKNXVVbm5NZHdVTytlRUY4eVU3cEdEUm04S2FSSER2QWF5SU0rbmloTkFsK2pJekFoTUE0R0ExVWREd0VCL3dRRQpBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSVFEMCtNT2piSXdxCm1ES3YveVVlSkFXVTVSemp0d3hmSHFmSjUwRnIrckxoMmdJZ0JWSjdMYkRwWXZKNEJDT3B5V0puMlJpRTBwY1IKZ0xZaUF1YlJNcXoxYU1jPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
certificate-authority: /Users/stephanbenny/code/src/github.com/RafaySystems/rafay-relay/testdata/certs/rootCA.crt
|
||||
server: https://cluster1.kubectl.relay.rafay.dev:443
|
||||
name: default
|
||||
contexts:
|
||||
- context:
|
||||
cluster: default
|
||||
user: default
|
||||
name: default
|
||||
current-context: default
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: default
|
||||
user:
|
||||
client-certificate: /Users/stephanbenny/code/src/github.com/RafaySystems/rafay-relay/testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.crt
|
||||
client-key: /Users/stephanbenny/code/src/github.com/RafaySystems/rafay-relay/testdata/certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.key
|
||||
#password: 15c80273fd3e8daae8a65ba86d8f6001
|
||||
#sername: admin
|
||||
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: logs-inspect
|
||||
namespace: rafay-system
|
||||
spec:
|
||||
containers:
|
||||
- image: alpine:3.12
|
||||
name: logs
|
||||
command: ["tail", "-f", "/dev/null"]
|
||||
volumeMounts:
|
||||
- mountPath: /opt/rafay/audit
|
||||
name: audit-volume
|
||||
volumes:
|
||||
- name: audit-volume
|
||||
persistentVolumeClaim:
|
||||
claimName: rafay-relay-audit
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
data:
|
||||
clusterID: q72dg2g
|
||||
relays: '[{"token":"bqjjlq6g10l2b7fm3v50","addr":"api.sentry.rafay.local:11000","endpoint":"*.core-connector.relay.rafay.local:10002","name":"rafay-core-relay-agent","templateToken":"bqjjln6g10l2lvudmup0"}]'
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: relay-agent-config
|
||||
namespace: rafay-system
|
||||
Vendored
+70
@@ -0,0 +1,70 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: default
|
||||
namespace: rafay-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: relay-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: relay-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: relay-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: rafay-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: rafay-core-debug
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: core-debug-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: core-debug-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: relay-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: rafay-core-debug
|
||||
namespace: default
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNWakNDQWZ5Z0F3SUJBZ0lRSGdlWXlLaHlLWXNIY3E2TXNybG9HakFLQmdncWhrak9QUVFEQWpDQmlqRU0KTUFvR0ExVUVCaE1EVlZOQk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGhNUkl3RUFZRFZRUUhFd2xUZFc1dQplWFpoYkdVeEdqQVlCZ05WQkFvVEVWSmhabUY1SUZONWMzUmxiWE1nU1c1ak1SVXdFd1lEVlFRTEV3eFNZV1poCmVTQlRaVzUwY25reEhqQWNCZ05WQkFNVEZYSmhabUY1TFdOdmNtVXRjbVZzWVhrdGRYTmxjakFlRncweU1EQTAKTWpjeU1EQTBORFJhRncwek1EQTBNamN5TURBME5EUmFNSUdLTVF3d0NnWURWUVFHRXdOVlUwRXhFekFSQmdOVgpCQWdUQ2tOaGJHbG1iM0p1YVdFeEVqQVFCZ05WQkFjVENWTjFibTU1ZG1Gc1pURWFNQmdHQTFVRUNoTVJVbUZtCllYa2dVM2x6ZEdWdGN5QkpibU14RlRBVEJnTlZCQXNUREZKaFptRjVJRk5sYm5SeWVURWVNQndHQTFVRUF4TVYKY21GbVlYa3RZMjl5WlMxeVpXeGhlUzExYzJWeU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRQpqUDh3V3lBNHNGdkh0ZlRXd1E5U3d0MmlzMWZPVi80dXVHY0VJcHhob2hOdVppeWcydElkOWtKNnY3OHpKUStGCkJQNEU0bkc0OFE0M0t2elhnS1JYVktOQ01FQXdEZ1lEVlIwUEFRSC9CQVFEQWdLRU1CMEdBMVVkSlFRV01CUUcKQ0NzR0FRVUZCd01DQmdnckJnRUZCUWNEQVRBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUFvR0NDcUdTTTQ5QkFNQwpBMGdBTUVVQ0lRQy9tTmZiamhUVWN4L1BtbFdLSzYxMk9XejJNaTRqdytqVnN6SXZ2Z3lYWkFJZ2RtQ0wvTjd6CkMvSk1raDVkamx5RFhrMU53cUVUS04xeU52NVZpSjBGVlA0PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
server: https://q72dg2g.user.relay.rafay.local:10002
|
||||
name: c-5
|
||||
contexts:
|
||||
- context:
|
||||
cluster: c-5
|
||||
user: rafay-core-debug
|
||||
name: c-5
|
||||
current-context: c-5
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: rafay-core-debug
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ5ekNDQVhHZ0F3SUJBZ0lRZS8wbHdYYVZLR0pkcXBnSnFFQUNxakFLQmdncWhrak9QUVFEQWpDQmlqRU0KTUFvR0ExVUVCaE1EVlZOQk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGhNUkl3RUFZRFZRUUhFd2xUZFc1dQplWFpoYkdVeEdqQVlCZ05WQkFvVEVWSmhabUY1SUZONWMzUmxiWE1nU1c1ak1SVXdFd1lEVlFRTEV3eFNZV1poCmVTQlRaVzUwY25reEhqQWNCZ05WQkFNVEZYSmhabUY1TFdOdmNtVXRjbVZzWVhrdGRYTmxjakFlRncweU1EQTAKTWpjeU16QTVNamxhRncweU1EQTBNamd5TXpBNU1qbGFNQnN4R1RBWEJnTlZCQU1URUhKaFptRjVMV052Y21VdApaR1ZpZFdjd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRT2Z5bmZHR2NyYkgzRS9zSG12YmU2CjBtN1FuKzYyT0orRlhxWFhPREU2SzFuQzZSaVgzaUd1aDJjMlg0aGkyNk5ONk1aM1Uxemx5V3Rnb3dkazhzUDkKb3ljd0pUQU9CZ05WSFE4QkFmOEVCQU1DQmFBd0V3WURWUjBsQkF3d0NnWUlLd1lCQlFVSEF3SXdDZ1lJS29aSQp6ajBFQXdJRFNBQXdSUUloQUk1MTRLOHNXNE8wWnRqbkM5Nkp3dGRENlFCRUx6d2szMWtCUW8zaEw3MnZBaUEyCkE5YUgxVWFnaGxadnNybXpzM0UzaG1UdHJxSG9xZFZyQnVhMXFQclRWQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxsSW00Tk52VElVOFV3OTd3TnlKSmRZWjk0TmM2NGw1Y3lsRWRINjFONW9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFRG44cDN4aG5LMng5eFA3QjVyMjN1dEp1MEovdXRqaWZoVjZsMXpneE9pdFp3dWtZbDk0aApyb2RuTmwrSVl0dWpUZWpHZDFOYzVjbHJZS01IWlBMRC9RPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
||||
@@ -0,0 +1 @@
|
||||
curl -kv --cert ../certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.crt --key ../certs/clientcerts/relayserver1-ABCD-123456.relay.rafay.dev.key https://cluster1.kubectldialin.relay.rafay.dev/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user