Skip to content

Commit

Permalink
Sizeable refactor
Browse files Browse the repository at this point in the history
Create ./pkg for different source packages. Seperate code out into model, slosilo, server and utils packages. Introduce conjurctl CLI cmd as the common interface for consuming this application.
  • Loading branch information
doodlesbykumbi committed Apr 18, 2021
1 parent a955f7b commit 12fb1a6
Show file tree
Hide file tree
Showing 23 changed files with 1,017 additions and 430 deletions.
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ you're good to Go :_)
Currently supports
+ authn, authz, secret retrieval

Like Conjur in Ruby, this server uses the data key to decrypt all the things (secrets, tokenSigningPrivateKey etc.) from the database.
Like Conjur in Ruby, this server uses the datakey to decrypt/encrypt all the things (secrets, tokenSigningPrivateKey etc.) from and to the database.

Authn, though it doesn't verify your api key it allows you to assume the user you pass in.
Like Conjur the account needs an associated tokenSigningPrivateKey in the slosilo keystore.
The token is used both to sign new access tokens, and to verify access tokens as part of authz.
Also supports base64 encoding of the token.
```shell
curl -X POST \
-H 'ccept-Encoding: base64' \
-H 'Accept-Encoding: base64' \
-v \
"http://localhost:8000/authn/myConjurAccount/Dave@BotApp/authenticate"
```
Expand All @@ -31,6 +31,18 @@ curl \
"http://localhost:8000/secrets/myConjurAccount/variable/BotApp%2FsecretVar"
```

## Run

Build and run

```shell
go build -o conjurctl ./cmd/conjurctl

DATABASE_URL="postgres://postgres@localhost/postgres" \
CONJUR_DATA_KEY="2AP/N4ajPY3rsjpaIagjjA+JHjDbIw+hI+uI32jnrP4=" \
./conjurctl server
```

## Development

A great way to develop this project is to run `cyberark/conjur-quickstart`.
Expand Down Expand Up @@ -64,6 +76,6 @@ This really helps while tinkering. You can see all the tables and explore the Co

1. OpenTelemetry, get some metrics and traces going.
2. This could be used to create a lightweight "Conjur" that has a, say, in-memory backing
store for extremely fast reads. In this case the server needs to just do authn, authz and secrets fetching. Who knows the kinds of perfomance you could squeze.
store for extremely fast reads. In this case the server needs to just do authn, authz and secrets fetching. Who knows the kinds of performance you could squeeze.
3. Refactor + unit tests should be fun.

35 changes: 35 additions & 0 deletions cmd/conjurctl/data-key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

// dataKeyCmd represents the data-key command
var dataKeyCmd = &cobra.Command{
Use: "data-key",
Short: "Manage the data encryption key",
Long: `Manage the data encryption key`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("error: Command 'data-key' requires a subcommand generate")
fmt.Println()
cmd.Help()
os.Exit(1)
},
}

func init() {
rootCmd.AddCommand(dataKeyCmd)

// Here you will define your flags and configuration settings.

// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// dataKeyCmd.PersistentFlags().String("foo", "", "A help for foo")

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// dataKeyCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
34 changes: 34 additions & 0 deletions cmd/conjurctl/data-key>generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"encoding/base64"
"fmt"

"github.com/spf13/cobra"

"conjur-in-go/pkg/slosilo"
)

// dataKeyGenerateCmd represents the data-key > generate command
var dataKeyGenerateCmd = &cobra.Command{
Use: "generate",
Short: "Generate a data encryption key",
Long: `
Generate a data encryption key
Use this command to generate a new Base64-encoded 256 bit data encryption key. Once generated, this key should be placed into the environment of
the Conjur server. It will be used to encrypt all sensitive data which is stored in the database, including the token-signing private key.
Example:
$ export CONJUR_DATA_KEY="$(conjurctl data-key generate)"
`,
Run: func(cmd *cobra.Command, args []string) {
bytes, _ := slosilo.RandomBytes(32)
fmt.Printf("%s", base64.StdEncoding.Strict().EncodeToString(bytes))
},
}

func init() {
dataKeyCmd.AddCommand(dataKeyGenerateCmd)
}
5 changes: 5 additions & 0 deletions cmd/conjurctl/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package main

func main() {
Execute()
}
60 changes: 60 additions & 0 deletions cmd/conjurctl/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"github.com/spf13/cobra"
)

//var cfgFile string

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "conjurctl",
Short: "Command and control application for Conjur",
Long: `Command and control application for Conjur`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
cobra.CheckErr(rootCmd.Execute())
}

func init() {
cobra.OnInitialize(initConfig)

// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.

//rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.conjurctl.yaml)")

// Cobra also supports local flags, which will only run
// when this action is called directly.
//rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
//if cfgFile != "" {
// // Use config file from the flag.
// viper.SetConfigFile(cfgFile)
//} else {
// // Find home directory.
// home, err := homedir.Dir()
// cobra.CheckErr(err)
//
// // Search config in home directory with name ".conjurctl" (without extension).
// viper.AddConfigPath(home)
// viper.SetConfigName(".conjurctl")
//}
//
//viper.AutomaticEnv() // read in environment variables that match
//
//// If a config file is found, read it in.
//if err := viper.ReadInConfig(); err == nil {
// fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
//}
}
91 changes: 91 additions & 0 deletions cmd/conjurctl/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package main

import (
"encoding/base64"
"fmt"
"log"
"os"

"github.com/spf13/cobra"
"gorm.io/driver/postgres"
"gorm.io/gorm"

"conjur-in-go/pkg/server"
"conjur-in-go/pkg/server/endpoints"
"conjur-in-go/pkg/slosilo/store"
)


// NOTES
// tokenSigningPrivateKey is stored in slosilo keystore

const defaultBindAddress = "127.0.0.1"
const defaultPort = "8000"

// serverCmd represents the server command
var serverCmd = &cobra.Command{
Use: "server",
Short: "Run the Conjur application server",
Long: `Run the Conjur application server
To run the server requires the environment variables CONJUR_DATA_KEY and DATABASE_URL.`,
Run: func(cmd *cobra.Command, args []string) {
dataKeyB64, ok := os.LookupEnv("CONJUR_DATA_KEY")
if !ok {
fmt.Println("No CONJUR_DATA_KEY")
os.Exit(1)
}

dataKey, err := base64.StdEncoding.DecodeString(dataKeyB64)
if err != nil {
fmt.Println("Bad CONJUR_DATA_KEY:", err)
os.Exit(1)
}

db, err := gorm.Open(
postgres.New(
postgres.Config{
DSN: os.Getenv("DATABASE_URL"),
PreferSimpleProtocol: true, // disables implicit prepared statement usage
},
),
&gorm.Config{
},
)
if err != nil {
fmt.Println("Unable to connect to DB:", err)
os.Exit(1)
}

keystore, err := store.NewKeyStore(db, dataKey)
if err != nil {
fmt.Println("Unable to initiate keystore:", err)
os.Exit(1)
}

host, _ := cmd.Flags().GetString("bind-address")
port, _ := cmd.Flags().GetString("port")
s := server.NewServer(keystore, db, host, port)

endpoints.RegisterSecretReadEndpoint(s)
endpoints.RegisterAuthenticateEndpoint(s)

log.Printf("Running server at http://%s:%s...\n", host, port)
log.Fatal(s.Start())
},
}

func init() {
rootCmd.AddCommand(serverCmd)

// Here you will define your flags and configuration settings.

// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// serverCmd.PersistentFlags().String("foo", "", "A help for foo")

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
serverCmd.Flags().StringP("port", "p", defaultPort, "server listen port")
serverCmd.Flags().StringP("bind-address", "b", defaultBindAddress, "server bind address")
}
6 changes: 0 additions & 6 deletions config.go

This file was deleted.

3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ go 1.14
require (
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/mitchellh/go-homedir v1.1.0
github.com/spf13/cobra v1.1.3
github.com/spf13/viper v1.7.0
gorm.io/driver/postgres v1.0.8
gorm.io/gorm v1.21.8
)
Loading

0 comments on commit 12fb1a6

Please sign in to comment.