diff options
-rw-r--r-- | docs/coverage.html | 314 |
1 files changed, 205 insertions, 109 deletions
diff --git a/docs/coverage.html b/docs/coverage.html index 39ee191..883e4f6 100644 --- a/docs/coverage.html +++ b/docs/coverage.html @@ -54,17 +54,17 @@ <div id="nav"> <select id="files"> - <option value="file0">sms/auth/auth.go (76.1%)</option> + <option value="file0">sms/auth/auth.go (79.8%)</option> <option value="file1">sms/backend/backend.go (80.0%)</option> - <option value="file2">sms/backend/vault.go (72.5%)</option> + <option value="file2">sms/backend/vault.go (68.6%)</option> <option value="file3">sms/config/config.go (78.6%)</option> - <option value="file4">sms/handler/handler.go (63.0%)</option> + <option value="file4">sms/handler/handler.go (62.0%)</option> - <option value="file5">sms/log/logger.go (65.6%)</option> + <option value="file5">sms/log/logger.go (78.1%)</option> <option value="file6">sms/sms.go (77.8%)</option> @@ -113,25 +113,27 @@ import ( "crypto/tls" "crypto/x509" "encoding/base64" + "encoding/pem" "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/packet" "io/ioutil" + smsconfig "sms/config" smslogger "sms/log" ) // GetTLSConfig initializes a tlsConfig using the CA's certificate // This config is then used to enable the server for mutual TLS -func GetTLSConfig(caCertFile string) (*tls.Config, error) <span class="cov10" title="3">{ +func GetTLSConfig(caCertFile string, certFile string, keyFile string) (*tls.Config, error) <span class="cov8" title="3">{ // Initialize tlsConfig once caCert, err := ioutil.ReadFile(caCertFile) - if err != nil </span><span class="cov1" title="1">{ + if smslogger.CheckError(err, "Read CA Cert file") != nil </span><span class="cov1" title="1">{ return nil, err }</span> - <span class="cov6" title="2">caCertPool := x509.NewCertPool() + <span class="cov5" title="2">caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) tlsConfig := &tls.Config{ @@ -140,15 +142,66 @@ func GetTLSConfig(caCertFile string) (*tls.Config, error) <span class="cov10" ti ClientCAs: caCertPool, MinVersion: tls.VersionTLS12, } - tlsConfig.BuildNameToCertificate() + + certPEMBlk, err := readPEMBlock(certFile) + if smslogger.CheckError(err, "Read Cert File") != nil </span><span class="cov0" title="0">{ + return nil, err + }</span> + + <span class="cov5" title="2">keyPEMBlk, err := readPEMBlock(keyFile) + if smslogger.CheckError(err, "Read Key File") != nil </span><span class="cov0" title="0">{ + return nil, err + }</span> + + <span class="cov5" title="2">tlsConfig.Certificates = make([]tls.Certificate, 1) + tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlk, keyPEMBlk) + if smslogger.CheckError(err, "Load x509 cert and key") != nil </span><span class="cov0" title="0">{ + return nil, err + }</span> + + <span class="cov5" title="2">tlsConfig.BuildNameToCertificate() return tlsConfig, nil</span> } +func readPEMBlock(filename string) ([]byte, error) <span class="cov10" title="4">{ + + pemData, err := ioutil.ReadFile(filename) + + if smslogger.CheckError(err, "Read PEM File") != nil </span><span class="cov0" title="0">{ + return nil, err + }</span> + + <span class="cov10" title="4">pemBlock, rest := pem.Decode(pemData) + if len(rest) > 0 </span><span class="cov1" title="1">{ + smslogger.WriteWarn("Pemfile has extra data") + }</span> + + <span class="cov10" title="4">if x509.IsEncryptedPEMBlock(pemBlock) </span><span class="cov1" title="1">{ + pByte, err := base64.StdEncoding.DecodeString(smsconfig.SMSConfig.Password) + if smslogger.CheckError(err, "Decode PEM Password") != nil </span><span class="cov0" title="0">{ + return nil, err + }</span> + + <span class="cov1" title="1">pemData, err = x509.DecryptPEMBlock(pemBlock, pByte) + if smslogger.CheckError(err, "Decrypt PEM Data") != nil </span><span class="cov0" title="0">{ + return nil, err + }</span> + <span class="cov1" title="1">var newPEMBlock pem.Block + newPEMBlock.Type = pemBlock.Type + newPEMBlock.Bytes = pemData + // Converting back to PEM from DER data you get from + // DecryptPEMBlock + pemData = pem.EncodeToMemory(&newPEMBlock)</span> + } + + <span class="cov10" title="4">return pemData, nil</span> +} + // GeneratePGPKeyPair produces a PGP key pair and returns // two things: // A base64 encoded form of the public part of the entity // A base64 encoded form of the private key -func GeneratePGPKeyPair() (string, string, error) <span class="cov10" title="3">{ +func GeneratePGPKeyPair() (string, string, error) <span class="cov8" title="3">{ var entity *openpgp.Entity config := &packet.Config{ @@ -161,7 +214,7 @@ func GeneratePGPKeyPair() (string, string, error) <span class="cov10" title="3"> }</span> // Sign the identity in the entity - <span class="cov10" title="3">for _, id := range entity.Identities </span><span class="cov10" title="3">{ + <span class="cov8" title="3">for _, id := range entity.Identities </span><span class="cov8" title="3">{ err = id.SelfSignature.SignUserId(id.UserId.Id, entity.PrimaryKey, entity.PrivateKey, nil) if smslogger.CheckError(err, "Sign Entity") != nil </span><span class="cov0" title="0">{ return "", "", err @@ -169,14 +222,14 @@ func GeneratePGPKeyPair() (string, string, error) <span class="cov10" title="3"> } // Sign the subkey in the entity - <span class="cov10" title="3">for _, subkey := range entity.Subkeys </span><span class="cov10" title="3">{ + <span class="cov8" title="3">for _, subkey := range entity.Subkeys </span><span class="cov8" title="3">{ err := subkey.Sig.SignKey(subkey.PublicKey, entity.PrivateKey, nil) if smslogger.CheckError(err, "Sign Subkey") != nil </span><span class="cov0" title="0">{ return "", "", err }</span> } - <span class="cov10" title="3">buffer := new(bytes.Buffer) + <span class="cov8" title="3">buffer := new(bytes.Buffer) entity.Serialize(buffer) pbkey := base64.StdEncoding.EncodeToString(buffer.Bytes()) @@ -189,14 +242,14 @@ func GeneratePGPKeyPair() (string, string, error) <span class="cov10" title="3"> // EncryptPGPString takes data and a public key and encrypts using that // public key -func EncryptPGPString(data string, pbKey string) (string, error) <span class="cov6" title="2">{ +func EncryptPGPString(data string, pbKey string) (string, error) <span class="cov5" title="2">{ pbKeyBytes, err := base64.StdEncoding.DecodeString(pbKey) if smslogger.CheckError(err, "Decoding Base64 Public Key") != nil </span><span class="cov0" title="0">{ return "", err }</span> - <span class="cov6" title="2">dataBytes := []byte(data) + <span class="cov5" title="2">dataBytes := []byte(data) pbEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(pbKeyBytes))) if smslogger.CheckError(err, "Reading entity from PGP key") != nil </span><span class="cov0" title="0">{ @@ -204,23 +257,23 @@ func EncryptPGPString(data string, pbKey string) (string, error) <span class="co }</span> // encrypt string - <span class="cov6" title="2">buf := new(bytes.Buffer) + <span class="cov5" title="2">buf := new(bytes.Buffer) out, err := openpgp.Encrypt(buf, []*openpgp.Entity{pbEntity}, nil, nil, nil) if smslogger.CheckError(err, "Creating Encryption Pipe") != nil </span><span class="cov0" title="0">{ return "", err }</span> - <span class="cov6" title="2">_, err = out.Write(dataBytes) + <span class="cov5" title="2">_, err = out.Write(dataBytes) if smslogger.CheckError(err, "Writing to Encryption Pipe") != nil </span><span class="cov0" title="0">{ return "", err }</span> - <span class="cov6" title="2">err = out.Close() + <span class="cov5" title="2">err = out.Close() if smslogger.CheckError(err, "Closing Encryption Pipe") != nil </span><span class="cov0" title="0">{ return "", err }</span> - <span class="cov6" title="2">crp := base64.StdEncoding.EncodeToString(buf.Bytes()) + <span class="cov5" title="2">crp := base64.StdEncoding.EncodeToString(buf.Bytes()) return crp, nil</span> } @@ -258,24 +311,24 @@ func DecryptPGPString(data string, prKey string) (string, error) <span class="co // ReadFromFile reads a file and loads the PGP key into // a string -func ReadFromFile(fileName string) (string, error) <span class="cov6" title="2">{ +func ReadFromFile(fileName string) (string, error) <span class="cov1" title="1">{ data, err := ioutil.ReadFile(fileName) - if smslogger.CheckError(err, "Read from file") != nil </span><span class="cov0" title="0">{ + if smslogger.CheckError(err, "Read from file") != nil </span><span class="cov1" title="1">{ return "", err }</span> - <span class="cov6" title="2">return string(data), nil</span> + <span class="cov0" title="0">return string(data), nil</span> } // WriteToFile writes a PGP key into a file. // It will truncate the file if it exists -func WriteToFile(data string, fileName string) error <span class="cov0" title="0">{ +func WriteToFile(data string, fileName string) error <span class="cov5" title="2">{ err := ioutil.WriteFile(fileName, []byte(data), 0600) if smslogger.CheckError(err, "Write to file") != nil </span><span class="cov0" title="0">{ return err }</span> - <span class="cov0" title="0">return nil</span> + <span class="cov5" title="2">return nil</span> } </pre> @@ -406,7 +459,7 @@ type Vault struct { // Vault strcuture and populate it with the // right values and it will also create // a vault client -func (v *Vault) initVaultClient() error <span class="cov6" title="11">{ +func (v *Vault) initVaultClient() error <span class="cov7" title="11">{ vaultCFG := vaultapi.DefaultConfig() vaultCFG.Address = v.vaultAddress @@ -415,7 +468,7 @@ func (v *Vault) initVaultClient() error <span class="cov6" title="11">{ return err }</span> - <span class="cov6" title="11">v.initRoleDone = false + <span class="cov7" title="11">v.initRoleDone = false v.policyName = "smsvaultpolicy" v.vaultClient = client v.vaultMountPrefix = "sms" @@ -445,7 +498,7 @@ func (v *Vault) Init() error <span class="cov1" title="1">{ } // GetStatus returns the current seal status of vault -func (v *Vault) GetStatus() (bool, error) <span class="cov3" title="3">{ +func (v *Vault) GetStatus() (bool, error) <span class="cov2" title="2">{ sys := v.vaultClient.Sys() sealStatus, err := sys.SealStatus() @@ -453,7 +506,7 @@ func (v *Vault) GetStatus() (bool, error) <span class="cov3" title="3">{ return false, errors.New("Error getting status") }</span> - <span class="cov3" title="3">return sealStatus.Sealed, nil</span> + <span class="cov2" title="2">return sealStatus.Sealed, nil</span> } // RegisterQuorum registers the PGP public key for a quorum client @@ -498,14 +551,15 @@ func (v *Vault) Unseal(shard string) error <span class="cov0" title="0">{ // GetSecret returns a secret mounted on a particular domain name // The secret itself is referenced via its name which translates to // a mount path in vault -func (v *Vault) GetSecret(dom string, name string) (Secret, error) <span class="cov5" title="7">{ +func (v *Vault) GetSecret(dom string, name string) (Secret, error) <span class="cov2" title="2">{ err := v.checkToken() if smslogger.CheckError(err, "Tocken Check") != nil </span><span class="cov0" title="0">{ return Secret{}, errors.New("Token check failed") }</span> - <span class="cov5" title="7">dom = v.vaultMountPrefix + "/" + dom + <span class="cov2" title="2">dom = strings.TrimSpace(dom) + dom = v.vaultMountPrefix + "/" + dom sec, err := v.vaultClient.Logical().Read(dom + "/" + name) if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{ @@ -513,24 +567,25 @@ func (v *Vault) GetSecret(dom string, name string) (Secret, error) <span class=" }</span> // sec and err are nil in the case where a path does not exist - <span class="cov5" title="7">if sec == nil </span><span class="cov0" title="0">{ + <span class="cov2" title="2">if sec == nil </span><span class="cov0" title="0">{ smslogger.WriteWarn("Vault read was empty. Invalid Path") return Secret{}, errors.New("Secret not found at the provided path") }</span> - <span class="cov5" title="7">return Secret{Name: name, Values: sec.Data}, nil</span> + <span class="cov2" title="2">return Secret{Name: name, Values: sec.Data}, nil</span> } // ListSecret returns a list of secret names on a particular domain // The values of the secret are not returned -func (v *Vault) ListSecret(dom string) ([]string, error) <span class="cov3" title="3">{ +func (v *Vault) ListSecret(dom string) ([]string, error) <span class="cov2" title="2">{ err := v.checkToken() if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{ return nil, errors.New("Token check failed") }</span> - <span class="cov3" title="3">dom = v.vaultMountPrefix + "/" + dom + <span class="cov2" title="2">dom = strings.TrimSpace(dom) + dom = v.vaultMountPrefix + "/" + dom sec, err := v.vaultClient.Logical().List(dom) if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{ @@ -538,29 +593,29 @@ func (v *Vault) ListSecret(dom string) ([]string, error) <span class="cov3" titl }</span> // sec and err are nil in the case where a path does not exist - <span class="cov3" title="3">if sec == nil </span><span class="cov0" title="0">{ + <span class="cov2" title="2">if sec == nil </span><span class="cov0" title="0">{ smslogger.WriteWarn("Vaultclient returned empty data") return nil, errors.New("Secret not found at the provided path") }</span> - <span class="cov3" title="3">val, ok := sec.Data["keys"].([]interface{}) + <span class="cov2" title="2">val, ok := sec.Data["keys"].([]interface{}) if !ok </span><span class="cov0" title="0">{ smslogger.WriteError("Secret not found at the provided path") return nil, errors.New("Secret not found at the provided path") }</span> - <span class="cov3" title="3">retval := make([]string, len(val)) - for i, v := range val </span><span class="cov5" title="7">{ + <span class="cov2" title="2">retval := make([]string, len(val)) + for i, v := range val </span><span class="cov2" title="2">{ retval[i] = fmt.Sprint(v) }</span> - <span class="cov3" title="3">return retval, nil</span> + <span class="cov2" title="2">return retval, nil</span> } // Mounts the internal Domain if its not already mounted -func (v *Vault) mountInternalDomain(name string) error <span class="cov5" title="8">{ +func (v *Vault) mountInternalDomain(name string) error <span class="cov5" title="7">{ - if v.internalDomainMounted </span><span class="cov1" title="1">{ + if v.internalDomainMounted </span><span class="cov0" title="0">{ return nil }</span> @@ -575,8 +630,8 @@ func (v *Vault) mountInternalDomain(name string) error <span class="cov5" title= } err := v.vaultClient.Sys().Mount(mountPath, mountInput) - if smslogger.CheckError(err, "Mount internal Domain") != nil </span><span class="cov1" title="1">{ - if strings.Contains(err.Error(), "existing mount") </span><span class="cov1" title="1">{ + if smslogger.CheckError(err, "Mount internal Domain") != nil </span><span class="cov0" title="0">{ + if strings.Contains(err.Error(), "existing mount") </span><span class="cov0" title="0">{ // It is already mounted v.internalDomainMounted = true return nil @@ -585,13 +640,13 @@ func (v *Vault) mountInternalDomain(name string) error <span class="cov5" title= <span class="cov0" title="0">return errors.New("Unable to mount internal Domain")</span> } - <span class="cov5" title="6">v.internalDomainMounted = true + <span class="cov5" title="7">v.internalDomainMounted = true return nil</span> } // Stores the UUID created for secretdomain in vault // under v.vaultMountPrefix / smsinternal domain -func (v *Vault) storeUUID(uuid string, name string) error <span class="cov5" title="8">{ +func (v *Vault) storeUUID(uuid string, name string) error <span class="cov5" title="7">{ // Check if token is still valid err := v.checkToken() @@ -599,12 +654,12 @@ func (v *Vault) storeUUID(uuid string, name string) error <span class="cov5" tit return errors.New("Token Check failed") }</span> - <span class="cov5" title="8">err = v.mountInternalDomain(v.internalDomain) + <span class="cov5" title="7">err = v.mountInternalDomain(v.internalDomain) if smslogger.CheckError(err, "Mount Internal Domain") != nil </span><span class="cov0" title="0">{ return err }</span> - <span class="cov5" title="8">secret := Secret{ + <span class="cov5" title="7">secret := Secret{ Name: name, Values: map[string]interface{}{ "uuid": uuid, @@ -616,11 +671,11 @@ func (v *Vault) storeUUID(uuid string, name string) error <span class="cov5" tit return err }</span> - <span class="cov5" title="8">return nil</span> + <span class="cov5" title="7">return nil</span> } // CreateSecretDomain mounts the kv backend on a path with the given name -func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span class="cov5" title="8">{ +func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span class="cov5" title="7">{ // Check if token is still valid err := v.checkToken() @@ -628,7 +683,7 @@ func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span clas return SecretDomain{}, errors.New("Token Check failed") }</span> - <span class="cov5" title="8">name = strings.TrimSpace(name) + <span class="cov5" title="7">name = strings.TrimSpace(name) mountPath := v.vaultMountPrefix + "/" + name mountInput := &vaultapi.MountInput{ Type: "kv", @@ -643,7 +698,7 @@ func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span clas return SecretDomain{}, errors.New("Unable to create Secret Domain") }</span> - <span class="cov5" title="8">uuid, _ := uuid.GenerateUUID() + <span class="cov5" title="7">uuid, _ := uuid.GenerateUUID() err = v.storeUUID(uuid, name) if smslogger.CheckError(err, "Store UUID") != nil </span><span class="cov0" title="0">{ // Mount was successful at this point. @@ -653,19 +708,20 @@ func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span clas return SecretDomain{}, errors.New("Unable to store Secret Domain UUID. Retry") }</span> - <span class="cov5" title="8">return SecretDomain{uuid, name}, nil</span> + <span class="cov5" title="7">return SecretDomain{uuid, name}, nil</span> } // CreateSecret creates a secret mounted on a particular domain name // The secret itself is mounted on a path specified by name -func (v *Vault) CreateSecret(dom string, sec Secret) error <span class="cov7" title="18">{ +func (v *Vault) CreateSecret(dom string, sec Secret) error <span class="cov7" title="12">{ err := v.checkToken() if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{ return errors.New("Token check failed") }</span> - <span class="cov7" title="18">dom = v.vaultMountPrefix + "/" + dom + <span class="cov7" title="12">dom = strings.TrimSpace(dom) + dom = v.vaultMountPrefix + "/" + dom // Vault return is empty on successful write // TODO: Check if values is not empty @@ -674,38 +730,39 @@ func (v *Vault) CreateSecret(dom string, sec Secret) error <span class="cov7" ti return errors.New("Unable to create Secret at provided path") }</span> - <span class="cov7" title="18">return nil</span> + <span class="cov7" title="12">return nil</span> } // DeleteSecretDomain deletes a secret domain which translates to // an unmount operation on the given path in Vault -func (v *Vault) DeleteSecretDomain(name string) error <span class="cov3" title="3">{ +func (v *Vault) DeleteSecretDomain(dom string) error <span class="cov2" title="2">{ err := v.checkToken() if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{ return errors.New("Token Check Failed") }</span> - <span class="cov3" title="3">name = strings.TrimSpace(name) - mountPath := v.vaultMountPrefix + "/" + name + <span class="cov2" title="2">dom = strings.TrimSpace(dom) + mountPath := v.vaultMountPrefix + "/" + dom err = v.vaultClient.Sys().Unmount(mountPath) if smslogger.CheckError(err, "Delete Domain") != nil </span><span class="cov0" title="0">{ return errors.New("Unable to delete domain specified") }</span> - <span class="cov3" title="3">return nil</span> + <span class="cov2" title="2">return nil</span> } // DeleteSecret deletes a secret mounted on the path provided -func (v *Vault) DeleteSecret(dom string, name string) error <span class="cov5" title="7">{ +func (v *Vault) DeleteSecret(dom string, name string) error <span class="cov2" title="2">{ err := v.checkToken() if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{ return errors.New("Token check failed") }</span> - <span class="cov5" title="7">dom = v.vaultMountPrefix + "/" + dom + <span class="cov2" title="2">dom = strings.TrimSpace(dom) + dom = v.vaultMountPrefix + "/" + dom // Vault return is empty on successful delete _, err = v.vaultClient.Logical().Delete(dom + "/" + name) @@ -713,32 +770,32 @@ func (v *Vault) DeleteSecret(dom string, name string) error <span class="cov5" t return errors.New("Unable to delete Secret at provided path") }</span> - <span class="cov5" title="7">return nil</span> + <span class="cov2" title="2">return nil</span> } // initRole is called only once during SMS bring up // It initially creates a role and secret id associated with // that role. Later restarts will use the existing role-id // and secret-id stored on disk -func (v *Vault) initRole() error <span class="cov10" title="56">{ +func (v *Vault) initRole() error <span class="cov10" title="36">{ - if v.initRoleDone </span><span class="cov9" title="48">{ + if v.initRoleDone </span><span class="cov9" title="28">{ return nil }</span> // Use the root token once here - <span class="cov5" title="8">v.vaultClient.SetToken(v.vaultToken) + <span class="cov6" title="8">v.vaultClient.SetToken(v.vaultToken) defer v.vaultClient.ClearToken() // Check if roleID and secretID has already been created rID, error := smsauth.ReadFromFile("auth/role") - if error != nil </span><span class="cov5" title="7">{ + if error != nil </span><span class="cov6" title="8">{ smslogger.WriteWarn("Unable to find RoleID. Generating...") - }</span><span class="cov1" title="1"> else { + }</span> else<span class="cov0" title="0"> { sID, error := smsauth.ReadFromFile("auth/secret") if error != nil </span><span class="cov0" title="0">{ smslogger.WriteWarn("Unable to find secretID. Generating...") - }</span><span class="cov1" title="1"> else { + }</span> else<span class="cov0" title="0"> { v.roleID = rID v.secretID = sID v.initRoleDone = true @@ -746,7 +803,7 @@ func (v *Vault) initRole() error <span class="cov10" title="56">{ }</span> } - <span class="cov5" title="7">rules := `path "sms/*" { capabilities = ["create", "read", "update", "delete", "list"] } + <span class="cov6" title="8">rules := `path "sms/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "sys/mounts/sms*" { capabilities = ["update","delete","create"] }` err := v.vaultClient.Sys().PutPolicy(v.policyName, rules) if smslogger.CheckError(err, "Creating Policy") != nil </span><span class="cov0" title="0">{ @@ -754,13 +811,13 @@ func (v *Vault) initRole() error <span class="cov10" title="56">{ }</span> //Check if applrole is mounted - <span class="cov5" title="7">authMounts, err := v.vaultClient.Sys().ListAuth() + <span class="cov6" title="8">authMounts, err := v.vaultClient.Sys().ListAuth() if smslogger.CheckError(err, "Mount Auth Backend") != nil </span><span class="cov0" title="0">{ return errors.New("Unable to get mounted auth backends") }</span> - <span class="cov5" title="7">approleMounted := false - for k, v := range authMounts </span><span class="cov5" title="7">{ + <span class="cov6" title="8">approleMounted := false + for k, v := range authMounts </span><span class="cov6" title="8">{ if v.Type == "approle" && k == "approle/" </span><span class="cov0" title="0">{ approleMounted = true break</span> @@ -768,11 +825,11 @@ func (v *Vault) initRole() error <span class="cov10" title="56">{ } // Mount approle in case its not already mounted - <span class="cov5" title="7">if !approleMounted </span><span class="cov5" title="7">{ + <span class="cov6" title="8">if !approleMounted </span><span class="cov6" title="8">{ v.vaultClient.Sys().EnableAuth("approle", "approle", "") }</span> - <span class="cov5" title="7">rName := v.vaultMountPrefix + "-role" + <span class="cov6" title="8">rName := v.vaultMountPrefix + "-role" data := map[string]interface{}{ "token_ttl": "60m", "policies": [2]string{"default", v.policyName}, @@ -784,7 +841,7 @@ func (v *Vault) initRole() error <span class="cov10" title="56">{ if smslogger.CheckError(err, "Create RoleID") != nil </span><span class="cov0" title="0">{ return errors.New("Unable to create role ID for approle") }</span> - <span class="cov5" title="7">v.roleID = sec.Data["role_id"].(string) + <span class="cov6" title="8">v.roleID = sec.Data["role_id"].(string) // Create a secret-id to go with it sec, err = v.vaultClient.Logical().Write("auth/approle/role/"+rName+"/secret-id", @@ -793,7 +850,7 @@ func (v *Vault) initRole() error <span class="cov10" title="56">{ return errors.New("Unable to create secret ID for role") }</span> - <span class="cov5" title="7">v.secretID = sec.Data["secret_id"].(string) + <span class="cov6" title="8">v.secretID = sec.Data["secret_id"].(string) v.initRoleDone = true /* * Revoke the Root token. @@ -803,14 +860,14 @@ func (v *Vault) initRole() error <span class="cov10" title="56">{ err = v.vaultClient.Auth().Token().RevokeSelf(v.vaultToken) if smslogger.CheckError(err, "Revoke Root Token") != nil </span><span class="cov0" title="0">{ smslogger.WriteWarn("Unable to Revoke Token") - }</span><span class="cov5" title="7"> else { + }</span> else<span class="cov6" title="8"> { // Revoked successfully and clear it v.vaultToken = "" }</span> // Store the role-id and secret-id // We will need this if SMS restarts - <span class="cov5" title="7">smsauth.WriteToFile(v.roleID, "auth/role") + <span class="cov6" title="8">smsauth.WriteToFile(v.roleID, "auth/role") smsauth.WriteToFile(v.secretID, "auth/secret") return nil</span> @@ -818,7 +875,7 @@ func (v *Vault) initRole() error <span class="cov10" title="56">{ // Function checkToken() gets called multiple times to create // temporary tokens -func (v *Vault) checkToken() error <span class="cov9" title="54">{ +func (v *Vault) checkToken() error <span class="cov9" title="34">{ v.Lock() defer v.Unlock() @@ -832,8 +889,8 @@ func (v *Vault) checkToken() error <span class="cov9" title="54">{ }</span> // Return immediately if token still has life - <span class="cov9" title="54">if v.vaultClient.Token() != "" && - time.Since(v.vaultTempTokenTTL) < time.Minute*50 </span><span class="cov9" title="47">{ + <span class="cov9" title="34">if v.vaultClient.Token() != "" && + time.Since(v.vaultTempTokenTTL) < time.Minute*50 </span><span class="cov9" title="27">{ return nil }</span> @@ -886,7 +943,7 @@ func (v *Vault) initializeVault() error <span class="cov2" title="2">{ if smslogger.CheckError(err, "Generating PGP Keys") != nil </span><span class="cov0" title="0">{ smslogger.WriteError("Error Generating PGP Keys. Vault Init will not use encryption!") - }</span><span class="cov1" title="1"> else { + }</span> else<span class="cov1" title="1"> { initReq.PGPKeys = []string{pbkey, pbkey, pbkey} initReq.RootTokenPGPKey = pbkey }</span> @@ -938,6 +995,7 @@ type SMSConfiguration struct { CAFile string `json:"cafile"` ServerCert string `json:"servercert"` ServerKey string `json:"serverkey"` + Password string `json:"password"` BackendAddress string `json:"smsdbaddress"` VaultToken string `json:"vaulttoken"` @@ -999,6 +1057,7 @@ import ( "github.com/gorilla/mux" "net/http" + uuid "github.com/hashicorp/go-uuid" smsbackend "sms/backend" smslogger "sms/log" ) @@ -1011,7 +1070,7 @@ type handler struct { } // createSecretDomainHandler creates a secret domain with a name provided -func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="3">{ +func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{ var d smsbackend.SecretDomain err := json.NewDecoder(r.Body).Decode(&d) @@ -1020,13 +1079,13 @@ func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Reques return }</span> - <span class="cov6" title="3">dom, err := h.secretBackend.CreateSecretDomain(d.Name) + <span class="cov6" title="2">dom, err := h.secretBackend.CreateSecretDomain(d.Name) if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{ http.Error(w, err.Error(), http.StatusInternalServerError) return }</span> - <span class="cov6" title="3">w.Header().Set("Content-Type", "application/json") + <span class="cov6" title="2">w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) err = json.NewEncoder(w).Encode(dom) if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{ @@ -1036,7 +1095,7 @@ func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Reques } // deleteSecretDomainHandler deletes a secret domain with the name provided -func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="3">{ +func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{ vars := mux.Vars(r) domName := vars["domName"] @@ -1046,11 +1105,11 @@ func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Reques return }</span> - <span class="cov6" title="3">w.WriteHeader(http.StatusNoContent)</span> + <span class="cov6" title="2">w.WriteHeader(http.StatusNoContent)</span> } // createSecretHandler handles creation of secrets on a given domain name -func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov10" title="7">{ +func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{ // Get domain name from URL vars := mux.Vars(r) domName := vars["domName"] @@ -1063,17 +1122,17 @@ func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) <sp return }</span> - <span class="cov10" title="7">err = h.secretBackend.CreateSecret(domName, b) + <span class="cov6" title="2">err = h.secretBackend.CreateSecret(domName, b) if smslogger.CheckError(err, "CreateSecretHandler") != nil </span><span class="cov0" title="0">{ http.Error(w, err.Error(), http.StatusInternalServerError) return }</span> - <span class="cov10" title="7">w.WriteHeader(http.StatusCreated)</span> + <span class="cov6" title="2">w.WriteHeader(http.StatusCreated)</span> } // getSecretHandler handles reading a secret by given domain name and secret name -func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov10" title="7">{ +func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{ vars := mux.Vars(r) domName := vars["domName"] secName := vars["secretName"] @@ -1084,7 +1143,7 @@ func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) <span return }</span> - <span class="cov10" title="7">w.Header().Set("Content-Type", "application/json") + <span class="cov6" title="2">w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(sec) if smslogger.CheckError(err, "GetSecretHandler") != nil </span><span class="cov0" title="0">{ http.Error(w, err.Error(), http.StatusInternalServerError) @@ -1093,7 +1152,7 @@ func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) <span } // listSecretHandler handles listing all secrets under a particular domain name -func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="3">{ +func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{ vars := mux.Vars(r) domName := vars["domName"] @@ -1104,7 +1163,7 @@ func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) <span }</span> // Creating an anonymous struct to store the returned list of data - <span class="cov6" title="3">var retStruct = struct { + <span class="cov6" title="2">var retStruct = struct { SecretNames []string `json:"secretnames"` }{ secList, @@ -1119,7 +1178,7 @@ func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) <span } // deleteSecretHandler handles deleting a secret by given domain name and secret name -func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov10" title="7">{ +func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{ vars := mux.Vars(r) domName := vars["domName"] secName := vars["secretName"] @@ -1130,18 +1189,18 @@ func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) <sp return }</span> - <span class="cov10" title="7">w.WriteHeader(http.StatusNoContent)</span> + <span class="cov6" title="2">w.WriteHeader(http.StatusNoContent)</span> } // statusHandler returns information related to SMS and SMS backend services -func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) <span class="cov7" title="4">{ +func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) <span class="cov10" title="3">{ s, err := h.secretBackend.GetStatus() if smslogger.CheckError(err, "StatusHandler") != nil </span><span class="cov0" title="0">{ http.Error(w, err.Error(), http.StatusInternalServerError) return }</span> - <span class="cov7" title="4">status := struct { + <span class="cov10" title="3">status := struct { Seal bool `json:"sealstatus"` }{ s, @@ -1188,6 +1247,7 @@ func (h handler) unsealHandler(w http.ResponseWriter, r *http.Request) <span cla // with their PGP public keys that are then used by sms for backend // initialization func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) <span class="cov1" title="1">{ + // Get shards to be used for unseal type registerStruct struct { PGPKey string `json:"pgpkey"` @@ -1224,9 +1284,42 @@ func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) <span c }</span> } +// healthCheckHandler runs a few commands on the backend and returns +// OK or not depending on the status of the backend +func (h handler) healthCheckHandler(w http.ResponseWriter, r *http.Request) <span class="cov1" title="1">{ + + sealed, err := h.secretBackend.GetStatus() + if smslogger.CheckError(err, "HealthCheck") != nil </span><span class="cov0" title="0">{ + http.Error(w, err.Error(), http.StatusInternalServerError) + return + }</span> + + // backend is sealed + <span class="cov1" title="1">if sealed == true </span><span class="cov0" title="0">{ + http.Error(w, "Secret Backend is not ready for operations", http.StatusInternalServerError) + return + }</span> + + // backend is not sealed + <span class="cov1" title="1">dname, _ := uuid.GenerateUUID() + dom, err := h.secretBackend.CreateSecretDomain(dname) + if smslogger.CheckError(err, "HealthCheck Create Domain") != nil </span><span class="cov0" title="0">{ + http.Error(w, err.Error(), http.StatusInternalServerError) + return + }</span> + + <span class="cov1" title="1">err = h.secretBackend.DeleteSecretDomain(dom.UUID) + if smslogger.CheckError(err, "HealthCheck Delete Domain") != nil </span><span class="cov0" title="0">{ + http.Error(w, err.Error(), http.StatusInternalServerError) + return + }</span> + + <span class="cov1" title="1">w.WriteHeader(http.StatusOK)</span> +} + // CreateRouter returns an http.Handler for the registered URLs // Takes an interface implementation as input -func CreateRouter(b smsbackend.SecretBackend) http.Handler <span class="cov4" title="2">{ +func CreateRouter(b smsbackend.SecretBackend) http.Handler <span class="cov6" title="2">{ h := handler{secretBackend: b} // Create a new mux to handle URL endpoints @@ -1240,6 +1333,7 @@ func CreateRouter(b smsbackend.SecretBackend) http.Handler <span class="cov4" ti router.HandleFunc("/v1/sms/quorum/unseal", h.unsealHandler).Methods("POST") router.HandleFunc("/v1/sms/quorum/register", h.registerHandler).Methods("POST") + router.HandleFunc("/v1/sms/healthcheck", h.healthCheckHandler).Methods("GET") router.HandleFunc("/v1/sms/domain", h.createSecretDomainHandler).Methods("POST") router.HandleFunc("/v1/sms/domain/{domName}", h.deleteSecretDomainHandler).Methods("DELETE") @@ -1315,11 +1409,11 @@ func WriteError(msg string) <span class="cov0" title="0">{ // WriteWarn writes output to the writer we have // defined during its creation with WARNING prefix -func WriteWarn(msg string) <span class="cov0" title="0">{ - if warnL != nil </span><span class="cov0" title="0">{ +func WriteWarn(msg string) <span class="cov2" title="2">{ + if warnL != nil </span><span class="cov2" title="2">{ warnL.Output(2, fmt.Sprintln(msg)) }</span> - <span class="cov0" title="0">if stdWarn != nil </span><span class="cov0" title="0">{ + <span class="cov2" title="2">if stdWarn != nil </span><span class="cov2" title="2">{ stdWarn.Output(2, fmt.Sprintln(msg)) }</span> } @@ -1336,8 +1430,8 @@ func WriteInfo(msg string) <span class="cov1" title="1">{ } //CheckError is a helper function to reduce -//repitition of error checkign blocks of code -func CheckError(err error, topic string) error <span class="cov10" title="116">{ +//repetition of error checking blocks of code +func CheckError(err error, topic string) error <span class="cov10" title="55">{ if err != nil </span><span class="cov1" title="1">{ msg := topic + ": " + err.Error() if errL != nil </span><span class="cov1" title="1">{ @@ -1348,7 +1442,7 @@ func CheckError(err error, topic string) error <span class="cov10" title="116">{ }</span> <span class="cov1" title="1">return err</span> } - <span class="cov9" title="115">return nil</span> + <span class="cov9" title="54">return nil</span> } </pre> @@ -1420,15 +1514,17 @@ func main() <span class="cov8" title="1">{ <span class="cov8" title="1">if smsConf.DisableTLS == true </span><span class="cov0" title="0">{ smslogger.WriteWarn("TLS is Disabled") err = httpServer.ListenAndServe() - }</span><span class="cov8" title="1"> else { - // TODO: Use CA certificate from AAF - tlsConfig, err := smsauth.GetTLSConfig(smsConf.CAFile) - if err != nil </span><span class="cov0" title="0">{ + }</span> else<span class="cov8" title="1"> { + // Populate TLSConfig with the certificates and privatekey + // information + tlsConfig, err := smsauth.GetTLSConfig(smsConf.CAFile, smsConf.ServerCert, smsConf.ServerKey) + if smslogger.CheckError(err, "Get TLS Configuration") != nil </span><span class="cov0" title="0">{ log.Fatal(err) }</span> <span class="cov8" title="1">httpServer.TLSConfig = tlsConfig - err = httpServer.ListenAndServeTLS(smsConf.ServerCert, smsConf.ServerKey)</span> + // empty strings because tlsconfig already has this information + err = httpServer.ListenAndServeTLS("", "")</span> } <span class="cov8" title="1">if err != nil && err != http.ErrServerClosed </span><span class="cov0" title="0">{ |