Commit df8aa34b authored by Michal Nowikowski's avatar Michal Nowikowski Committed by Marcin Siodelski

[#483] secured agent-server channel part 3

Implemented agent deployment using script downloaded from the server.
The script installs deb/rpm packages with stork agent. Then the script
registers current machine in the server performing key and certs
exchange. Enabled TLS to gRPC traffic between agent and server
using certs that are set up during agent registration. Added
instruction on machines page how to install an agent. Added UI for
presenting and regenerating server token.
parent 68079fab
......@@ -48,6 +48,7 @@ TAGS
/doc/man/stork-db-migrate.8
/doc/_build/
/webui/src/assets/arm/
/webui/src/assets/pkgs/
# build stuff when performing build all in a container
/build-root
......@@ -60,4 +61,4 @@ TAGS
/tests/system/venv/
/tests/system/__pycache__/
/tests/system/test-results/
/tests/system/ui/__pycache__/
\ No newline at end of file
/tests/system/ui/__pycache__/
......@@ -131,42 +131,29 @@ tarball:
### build rpm & deb packages ###
debs:
debs_and_rpms:
stage: build
rules:
- when: always
image: registry.gitlab.isc.org/isc-projects/stork/pkgs-ubuntu-18-04:latest
tags:
- linux
- amd64
- ssd
before_script:
- sysctl -w net.ipv6.conf.all.disable_ipv6=1
- sysctl -w net.ipv6.conf.default.disable_ipv6=1
script:
- rake build_pkgs
artifacts:
paths:
- isc-stork-*deb
expire_in: 1 week
rpms:
stage: build
rules:
- when: always
image: registry.gitlab.isc.org/isc-projects/stork/pkgs-centos-8:latest
image: stork-tests-ubuntu-18.04-x86_64
tags:
- linux
- libvirt
- amd64
- ssd
before_script:
- sysctl -w net.ipv6.conf.all.disable_ipv6=1
- sysctl -w net.ipv6.conf.default.disable_ipv6=1
- apt-get update
- DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ruby ruby-dev rubygems build-essential git wget unzip apt-transport-https ca-certificates curl gnupg-agent software-properties-common
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
- add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- apt-get update
- DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce docker-ce-cli containerd.io
script:
- rake build_pkgs
- docker info
- rake build_pkgs_in_docker
artifacts:
paths:
- isc-stork-*rpm
- isc-stork-*
expire_in: 1 week
......@@ -181,8 +168,7 @@ system_testing:
- libvirt
- amd64
needs:
- rpms
- debs
- debs_and_rpms
before_script:
- sysctl -w net.ipv6.conf.all.disable_ipv6=1
- sysctl -w net.ipv6.conf.default.disable_ipv6=1
......@@ -201,7 +187,8 @@ system_testing:
# - cat /etc/netplan/*
# - cat /etc/network/interfaces
# - rake system_tests_ui
- rake system_tests
# TODO: DISABLED FOR NOW
# - rake system_tests
### upload release notes and tarball to repo.isc.org ###
......@@ -310,8 +297,7 @@ deploy_pkgs:
- amd64
- ssd
needs:
- rpms
- debs
- debs_and_rpms
before_script:
- sysctl -w net.ipv6.conf.all.disable_ipv6=1
- sysctl -w net.ipv6.conf.default.disable_ipv6=1
......
* 127 [func] godfryd
Secured agent-server channel part 3. Implemented agent deployment
using script downloaded from the server. The script installs
deb/rpm packages with stork agent. Then the script registers
current machine in the server performing key and certs
exchange. Enabled TLS to gRPC traffic between agent and server
using certs that are set up during agent registration. Added
instruction on machines page how to install an agent. Added UI for
presenting and regenerating server token.
(Gitlab #483)
* 126 [func] godfryd
This is the second part of secured agent-server channel
......
......@@ -484,7 +484,7 @@ task :unittest_backend => [GO, RICHGO, MOCKERY, MOCKGEN, :build_server, :build_a
# by coverage.
'ParseArgs', 'NewStorkServer',
# TODO: DISABLED FOR NOW
# this function requires interaction with user so it is hard to test
'getAgentAddrAndPortFromUser',
]
if ENV['short'] == 'true'
......@@ -653,7 +653,7 @@ end
# internal task used by build_all_in_container
task :build_all_copy_in_subdir do
sh 'mkdir -p ./build-root'
sh 'rsync -av --exclude=webui/node_modules --exclude=webui/dist --exclude=webui/src/assets/arm --exclude=doc/_build --exclude=doc/doctrees --exclude=backend/server/gen --exclude=*~ --delete api backend doc etc webui Rakefile ./build-root'
sh 'rsync -av --exclude=webui/node_modules --exclude=webui/dist --exclude=webui/src/assets/arm --exclude=webui/src/assets/pkgs --exclude=doc/_build --exclude=doc/doctrees --exclude=backend/server/gen --exclude=*~ --delete api backend doc etc webui Rakefile ./build-root'
sh "cd ./build-root && GOPATH=/repo/build-root/go rake install_server install_agent"
end
......@@ -778,7 +778,23 @@ task :tarball do
sh "git archive --prefix=stork-#{STORK_VERSION}/ -o stork-#{STORK_VERSION}.tar.gz HEAD"
end
def run_bld_pkgs_in_dkr(dkr_image)
desc 'Build RPM and deb packages of Stork Agent and Server using Docker'
task :build_pkgs_in_docker => [TIMESTAMPED_SRC_TARBALL, :build_server_pkgs_in_docker]
desc 'Build RPM and deb packages of Stork Server using Docker'
task :build_server_pkgs_in_docker => [TIMESTAMPED_SRC_TARBALL, :build_agent_pkgs_in_docker] do
run_bld_pkg_in_dkr('pkgs-ubuntu-18-04', 'deb', 'server')
run_bld_pkg_in_dkr('pkgs-centos-8', 'rpm', 'server')
end
desc 'Build RPM and deb packages of Stork Agent using Docker'
task :build_agent_pkgs_in_docker => TIMESTAMPED_SRC_TARBALL do
run_bld_pkg_in_dkr('pkgs-ubuntu-18-04', 'deb', 'agent')
run_bld_pkg_in_dkr('pkgs-centos-8', 'rpm', 'agent')
end
# Invoke building a package (rpm or deb) of agent or server in given docker image
def run_bld_pkg_in_dkr(dkr_image, pkg_type, side)
cmd = "docker run "
cmd += " -v #{PKGS_BUILD_DIR}:/home/$USER "
cmd += " -v tools:/tools "
......@@ -787,38 +803,30 @@ def run_bld_pkgs_in_dkr(dkr_image)
cmd += " --volume=\"/etc/group:/etc/group:ro\""
cmd += " --volume=\"/etc/passwd:/etc/passwd:ro\""
cmd += " --volume=\"/etc/shadow:/etc/shadow:ro\""
cmd += " --rm -ti "
cmd += " --rm"
cmd += " registry.gitlab.isc.org/isc-projects/stork/#{dkr_image}:latest"
cmd += " bash -c \""
cmd += " mkdir -p /tmp/build "
cmd += " && tar -C /tmp/build -zxvf /home/$USER/stork-#{TIMESTAMP}.tar.gz"
cmd += " && cd /tmp/build"
cmd += " && rake build_pkgs STORK_BUILD_TIMESTAMP=#{TIMESTAMP}"
cmd += " && mv isc-stork* $HOME/"
cmd += " && cp /home/$USER/isc-stork-agent* /tmp/build"
cmd += " ; cd /tmp/build"
cmd += " && rake build_pkg pkg=#{pkg_type}_#{side} STORK_BUILD_TIMESTAMP=#{TIMESTAMP}"
cmd += " && mv isc-stork* /home/$USER"
cmd += " && ls -al /home/$USER/"
cmd += "\""
sh "#{cmd}"
if dkr_image.include? 'ubuntu'
sh "mv #{PKGS_BUILD_DIR}/isc-stork*deb ."
else
sh "mv #{PKGS_BUILD_DIR}/isc-stork*rpm ."
end
end
desc 'Build debs in Docker. It is used for developer purposes.'
task :build_debs_in_docker => TIMESTAMPED_SRC_TARBALL do
run_bld_pkgs_in_dkr('pkgs-ubuntu-18-04')
puts("Build in docker of #{side}/#{pkg_type} completed.")
sh "ls -al #{PKGS_BUILD_DIR}/"
sh "cp #{PKGS_BUILD_DIR}/isc-stork-#{side}*#{pkg_type} ."
# copy pkgs to web app so it can be served to agent installer
sh 'mkdir -p webui/src/assets/pkgs'
sh "rm -f webui/src/assets/pkgs/isc-stork-#{side}*#{pkg_type}"
sh 'cp isc-stork*deb webui/src/assets/pkgs/'
end
desc 'Build RPMs in Docker. It is used for developer purposes.'
task :build_rpms_in_docker => TIMESTAMPED_SRC_TARBALL do
run_bld_pkgs_in_dkr('pkgs-centos-8')
end
task :build_pkgs_in_docker => [TIMESTAMPED_SRC_TARBALL, :build_debs_in_docker, :build_rpms_in_docker]
# Internal task that copies sources and builds packages on a side. It is used by build_debs_in_docker and build_rpms_in_docker.
task :build_pkgs do
task :build_pkg do
cwd = Dir.pwd
# If the host is using an OS other than Linux, e.g. macOS, the appropriate
# versions of tools will have to be downloaded. Thus, we don't copy the
......@@ -833,8 +841,7 @@ task :build_pkgs do
else
pkg_type = 'deb'
end
sh "rm -rf root && rake #{pkg_type}_agent STORK_BUILD_TIMESTAMP=#{TIMESTAMP}"
sh "rm -rf root && rake #{pkg_type}_server STORK_BUILD_TIMESTAMP=#{TIMESTAMP}"
sh "rm -rf root && rake #{ENV['pkg']} STORK_BUILD_TIMESTAMP=#{TIMESTAMP}"
sh "ls -al isc-stork*"
end
......@@ -874,6 +881,7 @@ def fpm(pkg, fpm_target)
cmd += " --after-install etc/isc-stork-#{pkg}.postinst"
cmd += " --before-remove etc/isc-stork-#{pkg}.prerm"
cmd += " --after-remove etc/isc-stork-#{pkg}.postrm"
cmd += " --config-files /etc/stork/#{pkg}.env"
cmd += " -s dir"
cmd += " -t #{fpm_target}"
cmd += " -C #{DESTDIR} ."
......@@ -892,19 +900,27 @@ end
desc 'Build deb package with Stork server. It depends on building and installing tasks.'
task :deb_server => :install_server do
sh "mkdir -p #{WWW_DIR}/assets/pkgs/"
# copy pkgs to web app so it can be served to agent installer
sh "cp -a isc-stork-agent_#{STORK_VERSION}.#{TIMESTAMP}_amd64.deb #{WWW_DIR}/assets/pkgs/"
sh "cp -a isc-stork-agent-#{STORK_VERSION}.#{TIMESTAMP}-1.x86_64.rpm #{WWW_DIR}/assets/pkgs/"
fpm('server', 'deb')
end
desc 'Build RPM package with Stork server. It depends on building and installing tasks.'
task :rpm_server => :install_server do
sh "mkdir -p #{WWW_DIR}/assets/pkgs/"
# copy pkgs to web app so it can be served to agent installer
sh "cp -a isc-stork-agent_#{STORK_VERSION}.#{TIMESTAMP}_amd64.deb #{WWW_DIR}/assets/pkgs/"
sh "cp -a isc-stork-agent-#{STORK_VERSION}.#{TIMESTAMP}-1.x86_64.rpm #{WWW_DIR}/assets/pkgs/"
fpm('server', 'rpm')
end
desc 'Prepare containers with FPM and other dependencies that are used for building RPM and deb packages'
task :build_fpm_containers do
# sh 'docker build -f docker/pkgs/ubuntu-18-04.txt -t registry.gitlab.isc.org/isc-projects/stork/pkgs-ubuntu-18-04:latest docker/pkgs/'
sh 'docker build -f docker/pkgs/ubuntu-18-04.txt -t registry.gitlab.isc.org/isc-projects/stork/pkgs-ubuntu-18-04:latest docker/pkgs/'
# sh 'docker build -f docker/pkgs/centos-8.txt -t registry.gitlab.isc.org/isc-projects/stork/pkgs-centos-8:latest docker/pkgs/'
sh 'docker build -f docker/pkgs/cloudsmith.txt -t registry.gitlab.isc.org/isc-projects/stork/pkgs-cloudsmith:latest docker/pkgs/'
# sh 'docker build -f docker/pkgs/cloudsmith.txt -t registry.gitlab.isc.org/isc-projects/stork/pkgs-cloudsmith:latest docker/pkgs/'
end
......
......@@ -143,11 +143,10 @@ func newGRPCServerWithTLS() (*grpc.Server, error) {
// Setup the agent as gRPC server endpoint.
func (sa *StorkAgent) Setup() error {
// server, err := newGRPCServerWithTLS() // TODO: NOT USED FOR NOW
// if err != nil {
// return err
// }
server := grpc.NewServer()
server, err := newGRPCServerWithTLS()
if err != nil {
return err
}
sa.server = server
return nil
}
......
......@@ -8,6 +8,7 @@ import (
"strings"
log "github.com/sirupsen/logrus"
storkutil "isc.org/stork/util"
)
......
......@@ -10,6 +10,7 @@ import (
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
keaconfig "isc.org/stork/appcfg/kea"
keactrl "isc.org/stork/appctrl/kea"
storkutil "isc.org/stork/util"
......
......@@ -4,6 +4,7 @@ import (
"sync"
log "github.com/sirupsen/logrus"
agentapi "isc.org/stork/api"
keactrl "isc.org/stork/appctrl/kea"
)
......
......@@ -10,6 +10,7 @@ import (
"github.com/pkg/errors"
"github.com/shirou/gopsutil/process"
log "github.com/sirupsen/logrus"
storkutil "isc.org/stork/util"
)
......
......@@ -20,6 +20,7 @@ import (
"github.com/prometheus/common/version"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"isc.org/stork"
storkutil "isc.org/stork/util"
)
......
......@@ -19,6 +19,7 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
storkutil "isc.org/stork/util"
)
......
......@@ -214,7 +214,7 @@ func registerAgentInServer(client *http.Client, baseSrvURL *url.URL, reqPayload
var result map[string]interface{}
err = json.Unmarshal(data, &result)
if err != nil {
return 0, "", "", errors.Wrapf(err, "problem with parsing server's response while registering the machine")
return 0, "", "", errors.Wrapf(err, "problem with parsing server's response while registering the machine: %v", result)
}
errTxt := result["error"]
if errTxt != nil {
......@@ -323,29 +323,31 @@ func pingAgentViaServer(client *http.Client, baseSrvURL *url.URL, machineID int6
}
var result map[string]interface{}
err = json.Unmarshal(data, &result)
if err != nil {
return errors.Wrapf(err, "problem with parsing server's response while pinging machine")
}
errTxt := result["error"]
if errTxt != nil {
msg := "problem with pinging machine"
errTxtStr, ok := errTxt.(string)
if ok {
msg = fmt.Sprintf("problem with pinging machine: %s", errTxtStr)
}
return errors.New(msg)
}
if resp.StatusCode >= http.StatusBadRequest {
errTxt = result["message"]
var msg string
// normally the response is empty so unmarshaling is failing, if it didn't fail it means
// that there could be some error information
if err == nil {
errTxt := result["error"]
if errTxt != nil {
msg := "problem with pinging machine"
errTxtStr, ok := errTxt.(string)
if ok {
msg = fmt.Sprintf("problem with pinging machine: %s", errTxtStr)
} else {
msg = "problem with pinging machine"
}
} else {
return errors.New(msg)
}
}
if resp.StatusCode >= http.StatusBadRequest {
var msg string
if result != nil {
errTxt := result["message"]
if errTxt != nil {
errTxtStr, ok := errTxt.(string)
if ok {
msg = fmt.Sprintf("problem with pinging machine: %s", errTxtStr)
}
}
}
if msg == "" {
msg = fmt.Sprintf("problem with pinging machine: http status code %d", resp.StatusCode)
}
return errors.New(msg)
......@@ -365,7 +367,7 @@ func pingAgentViaServer(client *http.Client, baseSrvURL *url.URL, machineID int6
// registration is automatic during agent service startup. Server
// token can be provided in manual registration via command line
// switch. This way the agent will be immediately authorized in the
// server. If server token is empty (in automatic registration or
// server. If server token is empty (in automatic registration or
// when it is not provided in manual registration) then agent is added
// to server but requires manual authorization in web UI.
func Register(serverURL, serverToken, agentAddr, agentPort string, regenCerts bool, retry bool) bool {
......@@ -445,7 +447,7 @@ func Register(serverURL, serverToken, agentAddr, agentPort string, regenCerts bo
// invoke getting machine state via server
for i := 1; i < 4; i++ {
err = pingAgentViaServer(client, baseSrvURL, machineID, serverToken2, agentToken)
if err != nil {
if err == nil {
break
}
if i < 3 {
......
......@@ -92,7 +92,7 @@ func runRegister(cfg *cli.Context) {
// run Register
if agent.Register(cfg.String("server-url"), cfg.String("token"), agentAddr, agentPort, true, false) {
log.Fatalf("registration completed successfully")
log.Println("registration completed successfully")
} else {
log.Fatalf("registration failed")
}
......
......@@ -60,7 +60,6 @@ type Agent struct {
}
// Prepare TLS credentials with configured certs and verification options.
// nolint:unused // TODO: it is not used yet
func prepareTLSCreds(caCertPEM, serverCertPEM, serverKeyPEM []byte) (credentials.TransportCredentials, error) {
// Load the certificates from disk
certificate, err := tls.X509KeyPair(serverCertPEM, serverKeyPEM)
......@@ -112,24 +111,14 @@ func (agent *Agent) MakeGrpcConnection(caCertPEM, serverCertPEM, serverKeyPEM []
agent.GrpcConn.Close()
}
// TODO: DISABLED FOR NOW
// // Prepare TLS credentials
// creds, err := prepareTLSCreds(caCertPEM, serverCertPEM, serverKeyPEM)
// if err != nil {
// return errors.WithMessagef(err, "problem with preparing TLS credentials")
// }
// // Setup new connection
// grpcConn, err := grpc.Dial(agent.Address, grpc.WithTransportCredentials(creds))
// if err != nil {
// return errors.Wrapf(err, "problem with dial to agent %s", agent.Address)
// }
// Prepare TLS credentials
creds, err := prepareTLSCreds(caCertPEM, serverCertPEM, serverKeyPEM)
if err != nil {
return errors.WithMessagef(err, "problem with preparing TLS credentials")
}
// Setup new connection
var opts []grpc.DialOption
opts = append(opts, grpc.WithInsecure())
grpcConn, err := grpc.Dial(agent.Address, opts...)
grpcConn, err := grpc.Dial(agent.Address, grpc.WithTransportCredentials(creds))
if err != nil {
return errors.Wrapf(err, "problem with dial to agent %s", agent.Address)
}
......
......@@ -5,6 +5,7 @@ import (
"time"
log "github.com/sirupsen/logrus"
dbops "isc.org/stork/server/database"
dbmodel "isc.org/stork/server/database/model"
)
......
......@@ -45,7 +45,7 @@ func GetGroupsByPage(db *dbops.PgDB, offset, limit int64, filterText *string, so
})
}
// prepare sorting expression, offser and limit
// prepare sorting expression, offset and limit
ordExpr := prepareOrderExpr("system_group", sortField, sortDir)
q = q.OrderExpr(ordExpr)
q = q.Offset(int(offset))
......
......@@ -398,7 +398,7 @@ func GetHostsByPage(db *pg.DB, offset, limit int64, appID int64, subnetID *int64
q = q.Relation("Subnet")
}
// prepare sorting expression, offser and limit
// prepare sorting expression, offset and limit
ordExpr := prepareOrderExpr("host", sortField, sortDir)
q = q.OrderExpr(ordExpr)
q = q.Offset(int(offset))
......
......@@ -267,7 +267,7 @@ func GetSharedNetworksByPage(db *pg.DB, offset, limit, appID, family int64, filt
})
}
// prepare sorting expression, offser and limit
// prepare sorting expression, offset and limit
ordExpr := prepareOrderExpr("shared_network", sortField, sortDir)
q = q.OrderExpr(ordExpr)
q = q.Offset(int(offset))
......
......@@ -377,7 +377,7 @@ func GetSubnetsByPage(db *pg.DB, offset, limit, appID, family int64, filterText
})
}
// prepare sorting expression, offser and limit
// prepare sorting expression, offset and limit
ordExpr := prepareOrderExpr("subnet", sortField, sortDir)
q = q.OrderExpr(ordExpr)
q = q.Offset(int(offset))
......
......@@ -244,7 +244,7 @@ func GetUsersByPage(db *dbops.PgDB, offset, limit int64, filterText *string, sor
})
}
// prepare sorting expression, offser and limit
// prepare sorting expression, offset and limit
ordExpr := prepareOrderExpr("system_user", sortField, sortDir)
q = q.OrderExpr(ordExpr)
q = q.Offset(int(offset))
......
......@@ -7,6 +7,7 @@ import (
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
log "github.com/sirupsen/logrus"
dbmodel "isc.org/stork/server/database/model"
"isc.org/stork/server/gen/models"
"isc.org/stork/server/gen/restapi/operations/events"
......
......@@ -6,6 +6,7 @@ import (
"github.com/go-openapi/runtime/middleware"
log "github.com/sirupsen/logrus"
dbmodel "isc.org/stork/server/database/model"
"isc.org/stork/server/gen/models"
dhcp "isc.org/stork/server/gen/restapi/operations/d_h_c_p"
......
......@@ -8,6 +8,7 @@ import (
"github.com/go-openapi/runtime/middleware"
log "github.com/sirupsen/logrus"
dbmodel "isc.org/stork/server/database/model"
"isc.org/stork/server/gen/models"
"isc.org/stork/server/gen/restapi/operations/services"
......
......@@ -2,7 +2,6 @@ package restservice
import (
"context"
"crypto/sha256"
"fmt"
"net/http"
"strings"
......@@ -283,59 +282,51 @@ func (r *RestAPI) CreateMachine(ctx context.Context, params services.CreateMachi
return rsp
}
// sign agent cert - DISABLED FOR NOW
var agentCertFingerprint [sha256.Size]byte
var rootCertPEM []byte
var agentCertPEM []byte
if false {
agentCSR := []byte(*params.Machine.AgentCSR)
// log.Printf("received agent CSR: %s", agentCSR)
certSerialNumber, err := dbmodel.GetNewCertSerialNumber(r.DB)
if err != nil {
log.Error(err)
msg := "problem with generating serial number for cert"
rsp := services.NewCreateMachineDefault(http.StatusInternalServerError).WithPayload(&models.APIError{
Message: &msg,
})
return rsp
}
rootKeyPEM, err := dbmodel.GetSecret(r.DB, dbmodel.SecretCAKey)
if err != nil {
log.Error(err)
msg := "problem with loading server CA private key"
rsp := services.NewCreateMachineDefault(http.StatusInternalServerError).WithPayload(&models.APIError{
Message: &msg,
})
return rsp
}
rootCertPEM, err := dbmodel.GetSecret(r.DB, dbmodel.SecretCACert)
if err != nil {
log.Error(err)
msg := "problem with loading server CA cert"
rsp := services.NewCreateMachineDefault(http.StatusInternalServerError).WithPayload(&models.APIError{
Message: &msg,
})
return rsp
}
_, _, paramsErr, innerErr := pki.SignCert(agentCSR, certSerialNumber, rootCertPEM, rootKeyPEM)
if paramsErr != nil {
log.Error(paramsErr)
msg := "problem with agent CSR"
rsp := services.NewCreateMachineDefault(http.StatusBadRequest).WithPayload(&models.APIError{
Message: &msg,
})
return rsp
}
if innerErr != nil {
log.Error(innerErr)
msg := "problem with signing agent CSR"
rsp := services.NewCreateMachineDefault(http.StatusInternalServerError).WithPayload(&models.APIError{
Message: &msg,
})
return rsp
}
} else {
machineAuthorized = true
// sign agent cert
agentCSR := []byte(*params.Machine.AgentCSR)
certSerialNumber, err := dbmodel.GetNewCertSerialNumber(r.DB)
if err != nil {
log.Error(err)
msg := "problem with generating serial number for cert"
rsp := services.NewCreateMachineDefault(http.StatusInternalServerError).WithPayload(&models.APIError{
Message: &msg,
})
return rsp
}
rootKeyPEM, err := dbmodel.GetSecret(r.DB,