providers/vault/vault_service_generator.go (271 lines of code) (raw):

package vault import ( "errors" "fmt" "log" "regexp" "sort" "strings" "github.com/GoogleCloudPlatform/terraformer/terraformutils" vault "github.com/hashicorp/vault/api" ) type ServiceGenerator struct { //nolint terraformutils.Service client *vault.Client mountType string resource string } func (g *ServiceGenerator) setVaultClient() error { client, err := vault.NewClient(&vault.Config{Address: g.Args["address"].(string)}) if err != nil { return err } if g.Args["token"] != "" { client.SetToken(g.Args["token"].(string)) } g.client = client return nil } func (g *ServiceGenerator) InitResources() error { switch g.resource { case "secret_backend": return g.createSecretBackendResources() case "secret_backend_role": return g.createSecretBackendRoleResources() case "auth_backend": return g.createAuthBackendResources() case "auth_backend_role": return g.createAuthBackendEntityResources("role", "role") case "auth_backend_user": return g.createAuthBackendEntityResources("users", "user") case "auth_backend_group": return g.createAuthBackendEntityResources("groups", "group") case "policy": return g.createPolicyResources() case "generic_secret": return g.createGenericSecretResources() case "mount": return g.createMountResources() default: return errors.New("unsupported service type. shouldn't ever reach here") } } func (g *ServiceGenerator) createSecretBackendResources() error { mounts, err := g.mountsByType() if err != nil { return err } for _, mount := range mounts { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( mount, mount, fmt.Sprintf("vault_%s_secret_backend", g.mountType), g.ProviderName, []string{})) } return nil } func (g *ServiceGenerator) createSecretBackendRoleResources() error { mounts, err := g.mountsByType() if err != nil { return err } for _, mount := range mounts { path := fmt.Sprintf("%s/roles", mount) s, err := g.client.Logical().List(path) if err != nil { log.Printf("error calling path %s: %s", path, err) continue } if s == nil { log.Printf("call to %s returned nil result", path) continue } roles, ok := s.Data["keys"] if !ok { log.Printf("no keys in call to %s", path) continue } for _, role := range roles.([]interface{}) { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( fmt.Sprintf("%s/roles/%s", mount, role), fmt.Sprintf("%s_%s", mount, role), fmt.Sprintf("vault_%s_secret_backend_role", g.mountType), g.ProviderName, []string{})) } } return nil } func (g *ServiceGenerator) mountsByType() ([]string, error) { mounts, err := g.client.Sys().ListMounts() if err != nil { return nil, err } var typeMounts []string for name, mount := range mounts { if g.mountType == "" || mount.Type == g.mountType { id := strings.ReplaceAll(name, "/", "") typeMounts = append(typeMounts, id) } } return typeMounts, nil } func (g *ServiceGenerator) createAuthBackendResources() error { backends, err := g.backendsByType() if err != nil { return err } for _, backend := range backends { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( backend, backend, fmt.Sprintf("vault_%s_auth_backend", g.mountType), g.ProviderName, []string{})) } return nil } func (g *ServiceGenerator) createAuthBackendEntityResources(apiEntity, tfEntity string) error { backends, err := g.backendsByType() if err != nil { return err } for _, backend := range backends { path := fmt.Sprintf("/auth/%s/%s", backend, apiEntity) s, err := g.client.Logical().List(path) if err != nil { log.Printf("error calling path %s: %s", path, err) continue } if s == nil { log.Printf("call to %s returned nil result", path) continue } names, ok := s.Data["keys"] if !ok { log.Printf("no keys in call to %s", path) continue } for _, name := range names.([]interface{}) { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( fmt.Sprintf("auth/%s/%s/%s", backend, apiEntity, name), fmt.Sprintf("%s_%s", backend, name), fmt.Sprintf("vault_%s_auth_backend_%s", g.mountType, tfEntity), g.ProviderName, []string{})) } } return nil } func (g *ServiceGenerator) backendsByType() ([]string, error) { authBackends, err := g.client.Sys().ListAuth() if err != nil { return nil, err } var typeBackends []string for name, authBackend := range authBackends { if authBackend.Type != g.mountType { continue } id := strings.ReplaceAll(name, "/", "") typeBackends = append(typeBackends, id) } return typeBackends, nil } func (g *ServiceGenerator) createPolicyResources() error { policies, err := g.client.Sys().ListPolicies() if err != nil { return err } for _, policy := range policies { if policy == "root" { continue } g.Resources = append(g.Resources, terraformutils.NewSimpleResource( policy, policy, "vault_policy", g.ProviderName, []string{})) } return nil } func (g *ServiceGenerator) createGenericSecretResources() error { mounts, err := g.mountsByType() if err != nil { return err } for _, mount := range mounts { path := fmt.Sprintf("%s/", mount) s, err := g.client.Logical().List(path) if err != nil { log.Printf("error calling path %s: %s", path, err) continue } if s == nil { log.Printf("call to %s returned nil result", path) continue } secrets, ok := s.Data["keys"] if !ok { log.Printf("no keys in call to %s", path) continue } for _, secret := range secrets.([]interface{}) { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( fmt.Sprintf("%s/%s", mount, secret), fmt.Sprintf("%s_%s", mount, secret), "vault_generic_secret", g.ProviderName, []string{})) } } return nil } func (g *ServiceGenerator) createMountResources() error { mounts, err := g.mountsByType() if err != nil { return err } for _, mount := range mounts { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( mount, mount, "vault_mount", g.ProviderName, []string{})) } return nil } func (g *ServiceGenerator) PostConvertHook() error { for _, resource := range g.Resources { switch resource.InstanceInfo.Type { case "vault_aws_secret_backend_role": if policyDocument, ok := resource.Item["policy_document"]; ok { // borrowed from providers/aws/aws_service.go sanitizedPolicy := regexp.MustCompile(`(\${[0-9A-Za-z:]+})`). ReplaceAllString(policyDocument.(string), "$$$1") resource.Item["policy_document"] = fmt.Sprintf(`<<POLICY %s POLICY`, sanitizedPolicy) } case "vault_ldap_auth_backend_group": if policies, ok := resource.Item["policies"]; ok { var strPolicies []string for _, policy := range policies.([]interface{}) { strPolicies = append(strPolicies, policy.(string)) } sort.Strings(strPolicies) resource.Item["policies"] = strPolicies } } } return nil }