Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mTLS CA Option on tornjak server #43

Merged
merged 7 commits into from
Mar 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion run_server.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
echo "${@}"
/opt/spire/tornjak-agent -c $2 http &
/opt/spire/tornjak-agent -c /run/spire/config/server.conf http --tls --cert sample-keys/tls.pem --key sample-keys/key.pem --listen-addr :20000 &
/opt/spire/tornjak-agent -c /run/spire/config/server.conf http --mtls --cert sample-keys/mtls.pem --key sample-keys/key.pem --listen-addr :30000 &
/opt/spire/tornjak-agent -c /run/spire/config/server.conf http --mtls --cert sample-keys/tls.pem --key sample-keys/key.pem --mtls-ca sample-keys/rootCA.pem --listen-addr :30000 &
# PORT=3000 npm start --prefix ./tornjak-frontend &
/usr/bin/dumb-init /opt/spire/bin/spire-server run "${@}"
25 changes: 0 additions & 25 deletions sample-keys/ca_process/README

This file was deleted.

71 changes: 71 additions & 0 deletions sample-keys/ca_process/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Managing Certificate Authority (CA) for Tornjak

## Create a CA
Run `./create-ca.sh` to create a CA. It will put the necessary cert and key files in the `CA/` directory.

## Signing a cert
Certificates are required for TLS and mTLS connections with Tornjak server.

To create and sign a certificate run `./create-cert.sh <domain name> <name>`

Tornjak server example:

```console
./create-cert.sh *.mydomain.com roks1
```

This script creates `roks1.key` and `roks1.crt` files that represent
the key/cert pair to configure the server.

Client example:

```console
./create-cert.sh localhost client
```

This script creates `client.key` and `client.crt` files that represent
the key/cert pair to configure the client.

## Tornjak Server and Client configuration
* SPIRE with Tornjak represent Server.
* Browser, `curl`, or Tornjak Manager represent clients.

### For TLS

```
Client:
TLS: CA/rootCA.crt

Server:
TLS: roks1.key, roks1.crt
```

### For mTLS
```
Client:
TLS: CA/rootCA.crt
mTLS: client.key, client.crt

Server:
TLS: roks1.key, roks1.crt
mTLS: CA/rootCA.crt
```

# Examples
Secret to configure the Tornjak Server:
```console
kubectl -n tornjak create secret generic tornjak-certs \
--from-file=key.pem="roks1.key" \
--from-file=tls.pem="roks1.crt" \
--from-file=rootCA.pem="CA/rootCA.crt"
```

TLS client request:
```console
curl --cacert CA/rootCA.crt https://<Tornjak_TLS_endpoint>
```

mTLS client request:
```console
curl --cacert CA/rootCA.crt --key client.key --cert client.crt https://<Tornjak_TLS_endpoint>
```
23 changes: 22 additions & 1 deletion tornjak-backend/api/agent/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Server struct {
SpireServerAddr string
CertPath string
KeyPath string
MTlsCaPath string
TlsEnabled bool
MTlsEnabled bool

Expand Down Expand Up @@ -479,6 +480,20 @@ func (s *Server) HandleRequests() {
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

tlsType := "TLS"
// If mTLS is enabled, add mTLS CA path to cert pool as well
if s.MTlsCaPath != "" {
if _, err := os.Stat(s.MTlsCaPath); os.IsNotExist(err) {
log.Fatalf("File does not exist %s", s.MTlsCaPath)
}
mTLSCaCert, err := ioutil.ReadFile(s.MTlsCaPath)
if err != nil {
log.Fatal(err)
}
caCertPool.AppendCertsFromPEM(mTLSCaCert)
tlsType = "mTLS"
}

// Create the TLS Config with the CA pool and enable Client certificate validation

tlsConfig := &tls.Config{
Expand All @@ -496,7 +511,13 @@ func (s *Server) HandleRequests() {
TLSConfig: tlsConfig,
}

fmt.Printf("Starting to listen with TLS on %s...\n", s.ListenAddr)
fmt.Printf("Starting to listen with %s on %s...\n", tlsType, s.ListenAddr)
if _, err := os.Stat(s.CertPath); os.IsNotExist(err) {
log.Fatalf("File does not exist %s", s.CertPath)
}
if _, err := os.Stat(s.KeyPath); os.IsNotExist(err) {
log.Fatalf("File does not exist %s", s.KeyPath)
}
log.Fatal(server.ListenAndServeTLS(s.CertPath, s.KeyPath))
return
} else {
Expand Down
33 changes: 32 additions & 1 deletion tornjak-backend/api/manager/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ var (
jsonContentType string = "application/json"
)

const (
keyShowLen int = 40
certShowLen int = 50
)
mrsabath marked this conversation as resolved.
Show resolved Hide resolved

type Server struct {
listenAddr string
db managerdb.ManagerDB
Expand Down Expand Up @@ -72,7 +77,33 @@ func (s *Server) apiServerProxyFunc(apiPath string) func(w http.ResponseWriter,
retError(w, emsg, http.StatusBadRequest)
return
}
fmt.Printf("%+v\n", sinfo)

// Gather the certs and key into a map
cMap := make(map[string]string)
cMap["CA"] = string(sinfo.CA)
cMap["cert"] = string(sinfo.Cert)
cMap["key"] = string(sinfo.Key)

// Iterate through the map and trim the values for debugging.
// Show the endings only
for k, v := range cMap {
if k == "key" {
if len(v) > keyShowLen {
cMap[k] = "\n..." + v[len(v)-keyShowLen:]
}
} else {
if len(v) > certShowLen {
cMap[k] = "\n..." + v[len(v)-certShowLen:]
}
}
}
fmt.Printf("Name:%s\n Address:%s\n TLS:%t, mTLS:%t\n", sinfo.Name, sinfo.Address, sinfo.TLS, sinfo.MTLS)
if sinfo.TLS {
fmt.Printf("CA:%s\n", cMap["CA"])
}
if sinfo.MTLS {
fmt.Printf("Cert:%s\n Key:%s\n", cMap["cert"], cMap["key"])
}

client, err := sinfo.HttpClient()
if err != nil {
Expand Down
13 changes: 11 additions & 2 deletions tornjak-backend/cmd/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type cliOptions struct {
listenAddr string
certPath string
keyPath string
mtlsCaPath string
tls bool
mtls bool
}
Expand Down Expand Up @@ -63,17 +64,24 @@ func main() {
&cli.StringFlag{
Name: "cert",
Value: "",
Usage: "CA Cert path for TLS/mTLS",
Usage: "CA Cert path for TLS",
Destination: &opt.httpOptions.certPath,
Required: false,
},
&cli.StringFlag{
Name: "key",
Value: "",
Usage: "Key path for TLS/mTLS",
Usage: "Key path for TLS",
Destination: &opt.httpOptions.keyPath,
Required: false,
},
&cli.StringFlag{
Name: "mtls-ca",
Value: "",
Usage: "CA path for mTLS CA",
Destination: &opt.httpOptions.mtlsCaPath,
Required: false,
},
&cli.BoolFlag{
Name: "tls",
Value: false,
Expand Down Expand Up @@ -140,6 +148,7 @@ func runTornjakCmd(cmd string, opt cliOptions) error {
ListenAddr: opt.httpOptions.listenAddr,
CertPath: opt.httpOptions.certPath,
KeyPath: opt.httpOptions.keyPath,
MTlsCaPath: opt.httpOptions.mtlsCaPath,
TlsEnabled: opt.httpOptions.tls,
MTlsEnabled: opt.httpOptions.mtls,
SpireServerInfo: serverInfo,
Expand Down
1 change: 0 additions & 1 deletion tornjak-backend/pkg/manager/types/serverinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ func (s ServerInfo) HttpClient() (*http.Client, error) {
if len(s.Cert) == 0 || len(s.Key) == 0 {
return nil, errors.New("Cannot configure MTLS if not key or cert is provided")
}

cert, err := tls.X509KeyPair(s.Cert, s.Key)
if err != nil {
return nil, err
Expand Down