From 1437664685f67a14d4b31335690e3eb126f1ed4c Mon Sep 17 00:00:00 2001 From: Erik Reinert Date: Sun, 22 Mar 2020 12:52:46 -0700 Subject: [PATCH] #1: Implements sync policies logic from config --- .gitignore | 1 + docker-compose.yml | 23 +++++++++++++ file.go | 48 ++++++++++++++++++++++---- main.go | 18 ++++++++-- vault.go | 84 +++++++++++++++++++++++++++++++++++----------- 5 files changed, 144 insertions(+), 30 deletions(-) create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index c5499f9..aa20849 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ ### vaultsync ### +policies/ config.json # Created by https://www.gitignore.io/api/go,osx,vim,windows diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6779c76 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +services: + source: + cap_add: + - IPC_LOCK + environment: + VAULT_DEV_ROOT_TOKEN_ID: d23c2d2a-a6a8-4742-9b61-c8c9a5f1031b + image: vault:1.3.4 + ports: + - "127.0.0.1:8300:8200" + volumes: + - source:/vault/file + target: + environment: + VAULT_DEV_ROOT_TOKEN_ID: 709e007e-a35c-4b3d-8c86-e393fb851ace + image: vault:1.3.4 + ports: + - "127.0.0.1:8200:8200" + volumes: + - target:/vault/file +version: "3.7" +volumes: + source: + target: diff --git a/file.go b/file.go index 677f7a1..7dc3df4 100644 --- a/file.go +++ b/file.go @@ -2,11 +2,17 @@ package main import ( "encoding/json" + "fmt" "io/ioutil" + "os" + "path" + "path/filepath" + "strings" ) // ConfigAuth : auth configuration type ConfigAuth struct { + Address string `json:"address"` Credentials map[string]string `json:"credentials"` Method string `json:"method"` } @@ -22,15 +28,18 @@ type ConfigSecret struct { // Config : configuration for vaultsync type Config struct { - SourceAddr string `json:"vault_source_addr"` - SourceAuth ConfigAuth `json:"vault_source_auth"` - SourceSecrets []ConfigSecret `json:"vault_source_secrets"` - SourceToken string `json:"vault_source_token"` - TargetAddr string `json:"vault_target_addr"` - TargetToken string `json:"vault_target_token"` + SourceAuth ConfigAuth `json:"source_auth"` + SourceSecrets []ConfigSecret `json:"source_secrets"` + SourcePoliciesPath string `json:"source_policies_path"` + TargetAuth ConfigAuth `json:"target_auth"` } -// GetConfig : gets configuration +// FilenameWithoutExt : removes extension from filename +func FilenameWithoutExt(name string) string { + return strings.TrimSuffix(name, path.Ext(name)) +} + +// GetConfig : gets configuration from path func GetConfig(path string) (*Config, error) { data, err := ioutil.ReadFile(path) @@ -50,3 +59,28 @@ func GetConfig(path string) (*Config, error) { return &config, nil } + +// GetPolicies : gets all policies from path +func GetPolicies(path string) ([]os.FileInfo, error) { + policies := make([]os.FileInfo, 0) + + dir, err := ioutil.ReadDir(path) + + if err != nil { + return nil, err + } + + for _, f := range dir { + name := f.Name() + + file := fmt.Sprintf("%s/%s", path, name) + + extension := filepath.Ext(file) + + if extension == ".hcl" { + policies = append(policies, f) + } + } + + return policies, nil +} diff --git a/main.go b/main.go index e90c686..6a6a545 100644 --- a/main.go +++ b/main.go @@ -17,21 +17,33 @@ func main() { logrus.Fatal("invalid_config") } - client, err := NewClient(config.TargetAddr, config.TargetToken) + targetToken, err := Login(config.TargetAuth) if err != nil { logrus.Fatal(err) } - syncEnginesErr := SyncEngines(client, config) + targetClient, err := NewClient(config.TargetAuth.Address, *targetToken) + + if err != nil { + logrus.Fatal(err) + } + + syncEnginesErr := SyncEngines(targetClient, config) if syncEnginesErr != nil { logrus.Fatal(syncEnginesErr) } - syncSecretsErr := SyncSecrets(client, config) + syncSecretsErr := SyncSecrets(targetClient, config) if syncSecretsErr != nil { logrus.Fatal(syncSecretsErr) } + + syncPoliciesErr := SyncPolicies(targetClient, config) + + if syncEnginesErr != nil { + logrus.Fatal(syncPoliciesErr) + } } diff --git a/vault.go b/vault.go index 133188a..1570b4f 100644 --- a/vault.go +++ b/vault.go @@ -4,17 +4,20 @@ import ( "bytes" "encoding/json" "fmt" + "io/ioutil" "net/http" "github.com/hashicorp/vault/api" "github.com/sirupsen/logrus" ) +// AppRole : defines app role for authentication type AppRole struct { RoleID string `json:"role_id"` SecretID string `json:"secret_id"` } +// LoginAuthResult : defines vault successful login type LoginAuthResult struct { Accessor string `json:"accessor"` ClientToken string `json:"client_token"` @@ -29,31 +32,39 @@ type LoginResult struct { } // Login : login to Vault -func Login(config *Config) (*string, error) { - auth := AppRole{ - RoleID: config.SourceAuth.Credentials["role_id"], - SecretID: config.SourceAuth.Credentials["secret_id"], - } +func Login(auth ConfigAuth) (*string, error) { + var token string - data, err := json.Marshal(auth) + if auth.Method == "approle" { + approle := AppRole{ + RoleID: auth.Credentials["role_id"], + SecretID: auth.Credentials["secret_id"], + } - if err != nil { - return nil, err - } + data, err := json.Marshal(approle) - url := fmt.Sprintf("%s/v1/auth/approle/login", config.SourceAddr) + if err != nil { + return nil, err + } - resp, err := http.Post(url, "application/json", bytes.NewBuffer(data)) + url := fmt.Sprintf("%s/v1/auth/approle/login", auth.Address) - if err != nil { - return nil, err - } + resp, err := http.Post(url, "application/json", bytes.NewBuffer(data)) - var result LoginResult + if err != nil { + return nil, err + } + + var result LoginResult - json.NewDecoder(resp.Body).Decode(&result) + json.NewDecoder(resp.Body).Decode(&result) + + token = result.Auth.ClientToken + } - token := result.Auth.ClientToken + if auth.Method == "token" { + token = auth.Credentials["token"] + } return &token, nil } @@ -131,21 +142,54 @@ func SyncEngines(client *api.Client, config *Config) error { return nil } +// SyncPolicies : syncs policies to client Vault service +func SyncPolicies(client *api.Client, config *Config) error { + policies, err := GetPolicies(config.SourcePoliciesPath) + + if err != nil { + return err + } + + sys := client.Sys() + + for _, p := range policies { + filename := p.Name() + + path := fmt.Sprintf("%s/%s", config.SourcePoliciesPath, filename) + + policy, err := ioutil.ReadFile(path) + + if err != nil { + return err + } + + name := FilenameWithoutExt(filename) + + putErr := sys.PutPolicy(name, string(policy)) + + if putErr != nil { + return err + } + } + + return nil +} + // SyncSecrets : sync secrets from source to target func SyncSecrets(client *api.Client, config *Config) error { - token, err := Login(config) + sourceToken, err := Login(config.SourceAuth) if err != nil { return err } - sourceClient, err := NewClient(config.SourceAddr, config.SourceToken) + sourceClient, err := NewClient(config.SourceAuth.Address, *sourceToken) if err != nil { return err } - sourceClient.SetToken(*token) + sourceClient.SetToken(*sourceToken) source := sourceClient.Logical()