Skip to content

Commit

Permalink
chore(core): Adds go version of init-keys
Browse files Browse the repository at this point in the history
This is allows using the service with one fewer script

For now, it only implements creation of the two KAS keys, not the keycloak cert, which is more complex and requires running keytool or something similar as the go standard library doesn't seem to include the necessary formats
  • Loading branch information
dmihalcik-virtru committed Nov 5, 2024
1 parent f9d6f26 commit c76b4ae
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 6 deletions.
7 changes: 4 additions & 3 deletions .github/scripts/init-temp-keys.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ fi

mkdir -p "$opt_output"

openssl req -x509 -nodes -newkey RSA:2048 -subj "/CN=kas" -keyout "$opt_output/kas-private.pem" -out "$opt_output/kas-cert.pem" -days 365
openssl ecparam -name prime256v1 >ecparams.tmp
openssl req -x509 -nodes -newkey ec:ecparams.tmp -subj "/CN=kas" -keyout "$opt_output/kas-ec-private.pem" -out "$opt_output/kas-ec-cert.pem" -days 365
if ! go run github.com/opentdf/platform/service keys init -o="$opt_output" $( [ "$opt_verbose" == true ] && printf %s '-v' ); then
echo "[ERROR] keys init failed"
exit 1
fi

mkdir -p keys
openssl req -x509 -nodes -newkey RSA:2048 -subj "/CN=ca" -keyout keys/keycloak-ca-private.pem -out keys/keycloak-ca.pem -days 365
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
skip-cache: true
args: --out-format=colored-line-number
- if: matrix.directory == 'service'
run: .github/scripts/init-temp-keys.sh
run: go run ./service keys init
- run: go test ./... -short
working-directory: ${{ matrix.directory }}
- if: matrix.directory == 'service'
Expand Down
1 change: 1 addition & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2594,6 +2594,7 @@ oras.land/oras-go v1.2.0 h1:yoKosVIbsPoFMqAIFHTnrmOuafHal+J/r+I5bdbVWu4=
oras.land/oras-go v1.2.0/go.mod h1:pFNs7oHp2dYsYMSS82HaX5l4mpnGO7hbpPN6EWH2ltc=
oras.land/oras-go/v2 v2.3.1 h1:lUC6q8RkeRReANEERLfH86iwGn55lbSWP20egdFHVec=
oras.land/oras-go/v2 v2.3.1/go.mod h1:5AQXVEu1X/FKp1F9DMOb5ZItZBOa0y5dha0yCm4NR9c=
rbazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
Expand Down
127 changes: 127 additions & 0 deletions service/cmd/keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package cmd

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"os"
"time"

"github.com/spf13/cobra"
)

var (
verbose bool
output string
)

func init() {
keysCmd := cobra.Command{
Use: "keys",
Short: "Initialize and manage KAS public keys",
}

initCmd := &cobra.Command{
Use: "init",
Args: cobra.NoArgs,
RunE: func(_ *cobra.Command, _ []string) error {
return keysInit()
},
}
initCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "verbose logging")
initCmd.Flags().StringVarP(&output, "output", "o", ".", "directory to store new keys to")
keysCmd.AddCommand(initCmd)

rootCmd.AddCommand(&keysCmd)
}

func CertTemplate() (*x509.Certificate, error) {
// generate a random serial number (a real cert authority would have some logic behind this)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) //nolint:mnd // 128 bit uid is sufficiently unique
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, fmt.Errorf("failed to generate serial number [%w]", err)
}

tmpl := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{CommonName: "kas"},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour * 24 * 30 * 365), //nolint:mnd // About a year to expire
BasicConstraintsValid: true,
}
return &tmpl, nil
}

func storeKeyPair(priv, pub any, privateFile, publicFile string) error {
privateBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return fmt.Errorf("unable to marshal private key [%w]", err)
}
keyPEM := pem.EncodeToMemory(
&pem.Block{
Type: "PRIVATE KEY",
Bytes: privateBytes,
},
)
if err := os.WriteFile(privateFile, keyPEM, 0o400); err != nil {
return fmt.Errorf("unable to store key [%w]", err)
}

certTemplate, err := CertTemplate()
if err != nil {
return fmt.Errorf("unable to create cert template [%w]", err)
}

pubBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, pub, priv)
if err != nil {
return fmt.Errorf("unable to create cert [%w]", err)
}
_, err = x509.ParseCertificate(pubBytes)
if err != nil {
return fmt.Errorf("unable to parse cert [%w]", err)
}
// Encode public key to PKCS#1 ASN.1 PEM.
pubPEM := pem.EncodeToMemory(
&pem.Block{
Type: "CERTIFICATE",
Bytes: pubBytes,
},
)

if err := os.WriteFile(publicFile, pubPEM, 0o400); err != nil {
return fmt.Errorf("unable to store rsa public key [%w]", err)
}
return nil
}

func keysInit() error {
// openssl req -x509 -nodes -newkey RSA:2048
// -subj "/CN=kas" -keyout "$opt_output/kas-private.pem" -out "$opt_output/kas-cert.pem" -days 365
// Generate RSA key.
keyRSA, err := rsa.GenerateKey(rand.Reader, 2048) //nolint:mnd // 256 byte key
if err != nil {
return fmt.Errorf("unable to generate rsa key [%w]", err)
}
if err := storeKeyPair(keyRSA, keyRSA.Public(), output+"/kas-private.pem", output+"/kas-cert.pem"); err != nil {
return err
}

// openssl ecparam -name prime256v1 >ecparams.tmp
// openssl req -x509 -nodes -newkey ec:ecparams.tmp -subj "/CN=kas" -keyout "$opt_output/kas-ec-private.pem" -out "$opt_output/kas-ec-cert.pem" -days 365
keyEC, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return fmt.Errorf("failed to generate ECDSA private key [%w]", err)
}
if err := storeKeyPair(keyEC, keyEC.Public(), output+"/kas-ec-private.pem", output+"/kas-ec-cert.pem"); err != nil {
return err
}

return nil
}
3 changes: 1 addition & 2 deletions ubuntu.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ RUN make opentdf

FROM builder as tester

RUN apt-get update -y && apt-get install -y opensc openssl
RUN /scripts/init-temp-keys.sh
RUN /app/opentdf keys init

RUN make test

Expand Down

0 comments on commit c76b4ae

Please sign in to comment.