Skip to content
Snippets Groups Projects
Commit cdc3b8c9 authored by Fabian Seidl's avatar Fabian Seidl
Browse files

Resolve "Implement TLS support for SBI"

See merge request !508
parent f2e91bdc
Branches
Tags
1 merge request!508Resolve "Implement TLS support for SBI"
Pipeline #160026 passed with warnings
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
MAKEFILE_DIR := $(dir $(MAKEFILE_PATH))
TOOLS_DIR:= build-tools
TOOLS_DIR := build-tools
GOSDN_TMP_DIR := /tmp/gosdn
CLAB_DIR := $(GOSDN_TMP_DIR)/clab
GOSDN_PRG := $(MAKEFILE_DIR)$(TOOLS_DIR)
GOPATH := $(~/go)
GOBIN := $(GOSDN_PRG)
SCRIPTS_DIR := /scripts
GOCMD=go
GOBUILD=$(GOCMD) build
......@@ -138,25 +139,28 @@ containerize-hostname-checker-app:
containerize-ws-events-app:
docker buildx build --rm -t ws-events-app -f applications/ws-events/ws-events.Dockerfile .
containerlab-start: create-clab-dir containerize-all generate-gnmi-target-certs
containerlab-start: create-clab-dir containerize-all generate-all-certs
cd $(CLAB_DIR) &&\
sudo containerlab deploy --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn.clab.yaml
containerlab-slim-start: create-clab-dir containerize-all generate-gnmi-target-certs
containerlab-start-reconfigure: create-clab-dir containerize-all generate-all-certs
cd $(CLAB_DIR) &&\
sudo containerlab deploy --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn_slim.clab.yaml
sudo containerlab deploy --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn.clab.yaml --reconfigure
containerlab-slim-start-reconfigure: create-clab-dir containerize-all generate-gnmi-target-certs
containerlab-stop: create-clab-dir
cd $(CLAB_DIR) &&\
sudo containerlab deploy --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn_slim.clab.yaml --reconfigure
sudo containerlab destroy --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn.clab.yaml
containerlab-start-reconfigure: create-clab-dir containerize-all generate-gnmi-target-certs
containerlab-slim-start: create-clab-dir containerize-all generate-all-certs
cd $(CLAB_DIR) &&\
sudo containerlab deploy --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn.clab.yaml --reconfigure
sudo containerlab deploy --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn_slim.clab.yaml
containerlab-stop: create-clab-dir
containerlab-slim-start-reconfigure: create-clab-dir containerize-all generate-all-certs
cd $(CLAB_DIR) &&\
sudo containerlab destroy --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn.clab.yaml
sudo containerlab deploy --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn_slim.clab.yaml --reconfigure
containerlab-slim-start-configured: containerlab-slim-start
.$(SCRIPTS_DIR)/setup-clab-slim.sh -s true
containerlab-slim-stop: create-clab-dir
cd $(CLAB_DIR) &&\
......@@ -166,11 +170,33 @@ containerlab-graph: create-clab-dir
cd $(CLAB_DIR) &&\
sudo containerlab graph --topo $(MAKEFILE_DIR)dev_env_data/clab/gosdn.clab.yaml
generate-gnmi-target-certs: pre
generate-all-certs: pre generate-root-ca generate-gosdn-certs generate-gnmi-target-certs
generate-root-ca: pre
if [ ! -d "$(BUILD_ARTIFACTS_PATH)/ssl" ]; then \
mkdir -p $(BUILD_ARTIFACTS_PATH)/ssl/private; \
mkdir -p $(BUILD_ARTIFACTS_PATH)/ssl/certs; \
openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout $(BUILD_ARTIFACTS_PATH)/ssl/private/gnmi-target-selfsigned.key -out $(BUILD_ARTIFACTS_PATH)/ssl/certs/gnmi-target-selfsigned.crt; \
mkdir -p $(BUILD_ARTIFACTS_PATH)/ssl; \
openssl req -x509 -nodes -days 365 -newkey rsa:4096 -subj '/C=DE/O=H_DA/CN=ROOT_CA' \
-keyout $(BUILD_ARTIFACTS_PATH)/ssl/ca.key -out $(BUILD_ARTIFACTS_PATH)/ssl/ca.crt; \
fi
generate-gosdn-certs: pre
if [ ! -d "$(BUILD_ARTIFACTS_PATH)/ssl/gosdn" ]; then \
mkdir -p $(BUILD_ARTIFACTS_PATH)/ssl/gosdn/private; \
mkdir -p $(BUILD_ARTIFACTS_PATH)/ssl/gosdn/certs; \
openssl req -x509 -nodes -days 365 -newkey rsa:4096 -subj '/C=DE/O=H_DA/CN=GOSDN' \
-CA $(BUILD_ARTIFACTS_PATH)/ssl/ca.crt -CAkey $(BUILD_ARTIFACTS_PATH)/ssl/ca.key \
-keyout $(BUILD_ARTIFACTS_PATH)/ssl/gosdn/private/gosdn-selfsigned.key -out $(BUILD_ARTIFACTS_PATH)/ssl/gosdn/certs/gosdn-selfsigned.crt; \
cp $(BUILD_ARTIFACTS_PATH)/ssl/ca.crt $(BUILD_ARTIFACTS_PATH)/ssl/gosdn/ca.crt; \
fi
generate-gnmi-target-certs: pre generate-root-ca
if [ ! -d "$(BUILD_ARTIFACTS_PATH)/ssl/gnmi-target" ]; then \
mkdir -p $(BUILD_ARTIFACTS_PATH)/ssl/gnmi-target/private; \
mkdir -p $(BUILD_ARTIFACTS_PATH)/ssl/gnmi-target/certs; \
openssl req -x509 -nodes -days 365 -newkey rsa:4096 -subj '/C=DE/O=H_DA/CN=TARGET' \
-CA $(BUILD_ARTIFACTS_PATH)/ssl/ca.crt -CAkey $(BUILD_ARTIFACTS_PATH)/ssl/ca.key \
-keyout $(BUILD_ARTIFACTS_PATH)/ssl/gnmi-target/private/gnmi-target-selfsigned.key -out $(BUILD_ARTIFACTS_PATH)/ssl/gnmi-target/certs/gnmi-target-selfsigned.crt; \
cp $(BUILD_ARTIFACTS_PATH)/ssl/ca.crt $(BUILD_ARTIFACTS_PATH)/ssl/gnmi-target/ca.crt; \
fi
shell-gosdn:
......@@ -194,7 +220,6 @@ start-dev-env: containerize-gosdn containerize-plugin-registry
stop-dev-env:
./scripts/simple-dev-setup.sh --mode stop --topology dev_env_data/clab/basic_two_aristas.yaml
clean:
$(GOCLEAN)
rm -rf $(BUILD_ARTIFACTS_PATH)
......@@ -187,6 +187,8 @@ For goSDN:
- `defaultjwtduration`: duration of how long session tokens will be valid, provide an integer for the desired hours, example: 24 for tokens that should be valid for one day
- `log-level`: set to `'debug'` for a better level of information
- `help`: print the description of all available flags
- `tlscertfile`: path to a signed certificate, if set goSDN will use this in combination with a key file to setup TLS connections with communication partners
- `tlskeyfile`: path to a private key, if set goSDN will use this in combination with a signed cert file to setup TLS connections with communication partners
For the storage system:
......
......@@ -63,6 +63,7 @@ if they diverge from the default credentials (user:'admin' and pw:'arista').`,
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{},
},
Tls: tls,
}
switch opcode {
case "plugin":
......@@ -73,7 +74,13 @@ if they diverge from the default credentials (user:'admin' and pw:'arista').`,
opt.Type = spb.Type_TYPE_OPENCONFIG
}
resp, err := pndAdapter.AddNetworkElement(createContextWithAuthorization(), mneName, opt, uuid.MustParse(pluginID))
pluginUUID, err := uuid.Parse(pluginID)
if err != nil {
spinner.Fail(err)
return err
}
resp, err := pndAdapter.AddNetworkElement(createContextWithAuthorization(), mneName, opt, pluginUUID)
if err != nil {
spinner.Fail(err)
return err
......@@ -88,21 +95,25 @@ if they diverge from the default credentials (user:'admin' and pw:'arista').`,
PostRun: func(cmd *cobra.Command, args []string) {
// Necessary for prompt mode. The flag variables have to be resetted,
// since in prompt mode the program keeps running.
mneName, opcode, pluginID, address, username, password = "", "", "", "", "", ""
tls = false
},
}
var mneName string
var opcode string
var pluginID string
var tls bool
func init() {
networkElementCmd.AddCommand(networkElementCreateCmd)
networkElementCreateCmd.Flags().StringVar(&mneName, "name", "", "add a network element name (optional)")
networkElementCreateCmd.Flags().StringVar(&opcode, "type", "", "generation target (csbi or plugin)")
//networkElementCreateCmd.Flags().StringVar(&opcode, "type", "", "generation target (csbi or plugin)")
networkElementCreateCmd.Flags().StringVar(&pluginID, "plugin-id", "", "the plugin ID of the plugin to be used")
networkElementCreateCmd.Flags().StringVarP(&address, "address", "a", "", "address of a gnmi target, e.g. 192.168.1.1:6030")
networkElementCreateCmd.Flags().StringVarP(&username, "username", "u", "", "username for a gnmi resource")
networkElementCreateCmd.Flags().StringVarP(&password, "password", "p", "", "password for a gnmi resource")
networkElementCreateCmd.Flags().BoolVarP(&tls, "tls", "t", false, "use flag to enable the controller to send requests to network elements using tls")
}
......@@ -5,7 +5,6 @@ import (
"time"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
......@@ -27,6 +26,11 @@ const (
amqpPasswordKey = "amqpPassword"
amqpHostKey = "amqpHost"
amqpPortKey = "amqpPort"
// TLS.
tlsCertFileKey = "tlsCertFile"
tlsKeyFileKey = "tlsKeyFile"
tlsCACertFileKey = "tlsCACertFile"
)
// BasePndUUID is an uuid for the base PND.
......@@ -36,7 +40,7 @@ var BasePndUUID uuid.UUID
var ChangeTimeout time.Duration
// LogLevel ist the default log level.
var LogLevel logrus.Level
var LogLevel log.Level
// DatabaseConnection holds the credentials and address of the used database.
var DatabaseConnection string
......@@ -68,6 +72,15 @@ var AMQPPort string
// GNMISubscriptionsFilePath is the path to the file used for automated subscriptions.
var GNMISubscriptionsFilePath string
// CAFilePath is the path to the root CA file.
var CAFilePath string
// CertFilePath is the path to the signed certificate that the controller should use for TLS connections.
var CertFilePath string
// KeyFilePath si the path to the private key that the controller should use for TLS connections.
var KeyFilePath string
// Init gets called on module import.
func Init() {
err := InitializeConfig()
......@@ -112,6 +125,12 @@ func InitializeConfig() error {
loadAMQPConfig()
CAFilePath = getStringFromViper(tlsCACertFileKey)
CertFilePath = getStringFromViper(tlsCertFileKey)
KeyFilePath = getStringFromViper(tlsKeyFileKey)
if err := viper.WriteConfig(); err != nil {
return err
}
......@@ -165,9 +184,9 @@ func setChangeTimeout() error {
func setLogLevel() {
if os.Getenv("GOSDN_LOG") == "nolog" {
LogLevel = logrus.PanicLevel
LogLevel = log.PanicLevel
} else {
LogLevel = logrus.InfoLevel
LogLevel = log.InfoLevel
}
}
......
......@@ -7,7 +7,9 @@ socket = ":55055"
databaseConnection = "mongodb://root:example@clab-gosdn_csbi_arista_base-mongodb:27017"
filesystemPathToStores = "stores"
gNMISubscriptionsPath = "configs/gNMISubscriptions.txt"
tlscertfile = '/ssl/certs/gosdn-selfsigned.crt'
tlskeyfile = '/ssl/private/gosdn-selfsigned.key'
tlscacertfile = '/ssl/ca.crt'
amqpPrefix = "amqp://"
amqpUser = "guest"
......
......@@ -15,3 +15,6 @@ log-level = 'debug'
plugin-folder = 'plugins'
security = 'insecure'
socket = ':55055'
tlscertfile = '/ssl/certs/gosdn-selfsigned.crt'
tlskeyfile = '/ssl/private/gosdn-selfsigned.key'
tlscacertfile = '/ssl/ca.crt'
......@@ -53,8 +53,11 @@ type LoadedNetworkElement struct {
// TransportUsername is used for authentication via the transport method in use.
TransportUsername string `json:"transport_username,omitempty" bson:"transport_username,omitempty"`
// TransportPassword is used for authentication via the transport method in use.
TransportPassword string `json:"transport_password,omitempty" bson:"transport_password,omitempty"`
TransportOptionCsbi bool `json:"transport_option_csbi,omitempty" bson:"transport_option_csbi,omitempty"`
TransportPassword string `json:"transport_password,omitempty" bson:"transport_password,omitempty"`
// Note: deprecated, should be removed.
TransportOptionCsbi bool `json:"transport_option_csbi,omitempty" bson:"transport_option_csbi,omitempty"`
// TransportTLS uses TLS from the client side when if true.
TransportTLS bool `json:"transport_tls,omitempty" bson:"transport_tls,omitempty"`
// SBI indicates the southbound interface, which is used by this network element as UUID.
Plugin string `json:"plugin"`
......
......@@ -3,8 +3,10 @@ package nucleus
import (
"context"
"fmt"
"os"
"time"
"code.fbi.h-da.de/danet/gosdn/controller/config"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/change"
tpInterface "code.fbi.h-da.de/danet/gosdn/controller/interfaces/transport"
"code.fbi.h-da.de/danet/gosdn/controller/plugin/shared"
......@@ -54,6 +56,14 @@ func newGnmiTransport(opts *tpb.TransportOption, model shared.DeviceModel) (*Gnm
Encoding: gpb.Encoding_JSON_IETF,
Compression: opts.GetGnmiTransportOption().GetCompression(),
}
if opts.Tls {
if err := enableTLSInGnmiConfig(gnmiConfig); err != nil {
log.Error(err)
return nil, err
}
}
c, err := gnmi.Dial(gnmiConfig)
if err != nil {
return nil, err
......@@ -319,7 +329,6 @@ func (g *Gnmi) controlPlaneSubscribe(ctx context.Context, subscriptionInfo tpInt
}
return
default:
log.Infof("Buffer Length: %v", len(subInfoChannel))
time.Sleep(time.Millisecond * 2)
}
}
......@@ -349,3 +358,25 @@ func (g *Gnmi) SetPassthrough(ctx context.Context, req *gpb.SetRequest) (*gpb.Se
func (g *Gnmi) GetPassthrough(ctx context.Context, req *gpb.GetRequest) (*gpb.GetResponse, error) {
return g.client.Get(ctx, req)
}
func enableTLSInGnmiConfig(gnmiConfig *gnmi.Config) error {
wd, err := os.Getwd()
if err != nil {
return err
}
if config.CAFilePath != "" {
gnmiConfig.CertFile = wd + config.CAFilePath
} else {
return fmt.Errorf("Error setting up client with mTLS, required CA file not provided in config")
}
if config.CertFilePath != "" && config.KeyFilePath != "" {
gnmiConfig.CertFile = wd + config.CertFilePath
gnmiConfig.KeyFile = wd + config.KeyFilePath
} else {
return fmt.Errorf("Error setting up client with mTLS, required files not provided in config")
}
return nil
}
......@@ -230,6 +230,7 @@ func (n *CommonNetworkElement) MarshalJSON() ([]byte, error) {
var transportUsername string
var transportPassword string
var transportOptionType spb.Type
var transportTLS bool
// Handling of these cases is necessary as we use partial network elements for testing.
// eg. in most tests no transport or sbi is defined.
......@@ -240,12 +241,14 @@ func (n *CommonNetworkElement) MarshalJSON() ([]byte, error) {
transportUsername = "testing"
transportPassword = "testing"
transportOptionType = spb.Type_TYPE_OPENCONFIG
transportTLS = false
} else {
transportType = n.transport.Type()
transportAddress = n.transportOptions.Address
transportUsername = n.transportOptions.Username
transportPassword = n.transportOptions.Password
transportOptionType = n.transportOptions.Type
transportTLS = n.transportOptions.Tls
}
pluginUUID := n.Plugin.ID()
......@@ -271,6 +274,7 @@ func (n *CommonNetworkElement) MarshalJSON() ([]byte, error) {
TransportUsername string `json:"transport_username,omitempty"`
TransportPassword string `json:"transport_password,omitempty"`
TransportOptionType spb.Type `json:"transport_option"`
TransportTLS bool `json:"transport_tls"`
Plugin uuid.UUID `json:"plugin,omitempty"`
Model string `bson:"model,omitempty"`
PndID uuid.UUID `json:"pnd_id,omitempty"`
......@@ -282,6 +286,7 @@ func (n *CommonNetworkElement) MarshalJSON() ([]byte, error) {
TransportUsername: transportUsername,
TransportPassword: transportPassword,
TransportOptionType: transportOptionType,
TransportTLS: transportTLS,
Plugin: pluginUUID,
Model: string(modelAsString),
PndID: pndUUID,
......@@ -295,6 +300,7 @@ func (n *CommonNetworkElement) MarshalBSON() ([]byte, error) {
var transportUsername string
var transportPassword string
var transportOptionType spb.Type
var transportTLS bool
// Handling of these cases is necessary as we use partial network elements for testing.
// eg. in most tests no transport or sbi is defined.
......@@ -305,12 +311,14 @@ func (n *CommonNetworkElement) MarshalBSON() ([]byte, error) {
transportUsername = "testing"
transportPassword = "testing"
transportOptionType = spb.Type_TYPE_OPENCONFIG
transportTLS = false
} else {
transportType = n.transport.Type()
transportAddress = n.transportOptions.Address
transportUsername = n.transportOptions.Username
transportPassword = n.transportOptions.Password
transportOptionType = n.transportOptions.Type
transportTLS = n.transportOptions.Tls
}
pluginUUID := n.Plugin.ID()
......@@ -328,6 +336,7 @@ func (n *CommonNetworkElement) MarshalBSON() ([]byte, error) {
TransportUsername string `bson:"transport_username,omitempty"`
TransportPassword string `bson:"transport_password,omitempty"`
TransportOptionType spb.Type `bson:"transport_option"`
TransportTLS bool `bson:"transport_tls"`
Plugin string `bson:"plugin,omitempty"`
Model string `bson:"model,omitempty"`
PndID string `bson:"pnd_id,omitempty"`
......@@ -342,6 +351,7 @@ func (n *CommonNetworkElement) MarshalBSON() ([]byte, error) {
Plugin: pluginUUID.String(),
Model: modelAsString,
PndID: n.pndID.String(),
TransportTLS: transportTLS,
})
}
......
......@@ -226,6 +226,7 @@ func (s *NetworkElementService) createNetworkElementFromStore(loadedNetworkEleme
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{},
},
Tls: loadedNetworkElement.TransportTLS,
Type: spb.Type_TYPE_OPENCONFIG,
},
uuid.MustParse(loadedNetworkElement.PndID),
......
......@@ -44,12 +44,14 @@ topology:
mgmt-ipv4: 172.100.0.5
env:
GOSDN_ADMIN_PASSWORD: TestPassword
binds:
- ../../artifacts/ssl/gosdn:/app/ssl
gnmi-target:
kind: linux
image: registry.code.fbi.h-da.de/danet/gnmi-target/ubuntu:develop
binds:
- ../../artifacts/ssl:/etc/gnmi-target/ssl
- ../../artifacts/ssl/gnmi-target:/etc/gnmi-target/ssl
ports:
- 7030:7030
cmd:
......
......@@ -25,28 +25,30 @@ topology:
mgmt-ipv4: 172.100.0.5
env:
GOSDN_ADMIN_PASSWORD: TestPassword
binds:
- ../../artifacts/ssl/gosdn:/app/ssl
gnmi-target-switch0:
kind: linux
image: registry.code.fbi.h-da.de/danet/gnmi-target/ubuntu:develop
image: registry.code.fbi.h-da.de/danet/gnmi-target/debian:package
binds:
- ../../artifacts/ssl:/etc/gnmi-target/ssl
- ../../artifacts/ssl/gnmi-target:/etc/gnmi-target/ssl
ports:
- 7030:7030
cmd:
start --cert /etc/gnmi-target/ssl/certs/gnmi-target-selfsigned.crt --key /etc/gnmi-target/ssl/private/gnmi-target-selfsigned.key
start --ca_file /etc/gnmi-target/ssl/ca.crt --cert /etc/gnmi-target/ssl/certs/gnmi-target-selfsigned.crt --key /etc/gnmi-target/ssl/private/gnmi-target-selfsigned.key
mgmt-ipv4: 172.100.0.11
startup-delay: 5
gnmi-target-switch1:
kind: linux
image: registry.code.fbi.h-da.de/danet/gnmi-target/ubuntu:develop
image: registry.code.fbi.h-da.de/danet/gnmi-target/debian:package
binds:
- ../../artifacts/ssl:/etc/gnmi-target/ssl
- ../../artifacts/ssl/gnmi-target:/etc/gnmi-target/ssl
ports:
- 7031:7030
cmd:
start --cert /etc/gnmi-target/ssl/certs/gnmi-target-selfsigned.crt --key /etc/gnmi-target/ssl/private/gnmi-target-selfsigned.key
start --ca_file /etc/gnmi-target/ssl/ca.crt --cert /etc/gnmi-target/ssl/certs/gnmi-target-selfsigned.crt --key /etc/gnmi-target/ssl/private/gnmi-target-selfsigned.key
mgmt-ipv4: 172.100.0.12
startup-delay: 5
......
#!/bin/sh
## Note: This script does not clean up network elements already existing in the storage. Running it repeatedly will
## create a garbage storage.
GOSDNC_PATH="./artifacts/gosdnc"
GOSDNC_START=false
GOSDN_ADDRESS="172.100.0.5:55055"
ADMINPW="TestPassword"
OPENCONFIG_PLUGIN="d1c269a2-6482-4010-b0d8-679dff73153b"
## Adjust this if timer is to short.
SLEEP_TIMER=15
## Check for provided flags.
while getopts s: flag
do
case "${flag}" in
s) GOSDNC_START=${OPTARG};;
esac
done
## Sleep is needed to give gosdn some time to start correctly.
sleep $SLEEP_TIMER
## Call login and create entries for all the network elements.
## Could be a bit more automated in the future, but fine for now.
$GOSDNC_PATH login --controller $GOSDN_ADDRESS --u admin --p $ADMINPW
$GOSDNC_PATH mne create --address 172.100.0.11:7030 --name gnmi-target-switch0 --password admin --plugin-id $OPENCONFIG_PLUGIN --tls --username admin
$GOSDNC_PATH mne create --address 172.100.0.12:7030 --name gnmi-target-switch1 --password admin --plugin-id $OPENCONFIG_PLUGIN --tls --username admin
## Start gosdnc in prompt mode if GOSDNC_START=true
if $GOSDNC_START; then
$GOSDNC_PATH prompt
fi
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment