1package acl 2 3import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/consul/agent/structs" 8 "github.com/hashicorp/consul/api" 9) 10 11func GetTokenIDFromPartial(client *api.Client, partialID string) (string, error) { 12 if partialID == "anonymous" { 13 return structs.ACLTokenAnonymousID, nil 14 } 15 16 // the full UUID string was given 17 if len(partialID) == 36 { 18 return partialID, nil 19 } 20 21 tokens, _, err := client.ACL().TokenList(nil) 22 if err != nil { 23 return "", err 24 } 25 26 tokenID := "" 27 for _, token := range tokens { 28 if strings.HasPrefix(token.AccessorID, partialID) { 29 if tokenID != "" { 30 return "", fmt.Errorf("Partial token ID is not unique") 31 } 32 tokenID = token.AccessorID 33 } 34 } 35 36 if tokenID == "" { 37 return "", fmt.Errorf("No such token ID with prefix: %s", partialID) 38 } 39 40 return tokenID, nil 41} 42 43func GetPolicyIDFromPartial(client *api.Client, partialID string) (string, error) { 44 if partialID == "global-management" { 45 return structs.ACLPolicyGlobalManagementID, nil 46 } 47 // The full UUID string was given 48 if len(partialID) == 36 { 49 return partialID, nil 50 } 51 52 policies, _, err := client.ACL().PolicyList(nil) 53 if err != nil { 54 return "", err 55 } 56 57 policyID := "" 58 for _, policy := range policies { 59 if strings.HasPrefix(policy.ID, partialID) { 60 if policyID != "" { 61 return "", fmt.Errorf("Partial policy ID is not unique") 62 } 63 policyID = policy.ID 64 } 65 } 66 67 if policyID == "" { 68 return "", fmt.Errorf("No such policy ID with prefix: %s", partialID) 69 } 70 71 return policyID, nil 72} 73 74func GetPolicyIDByName(client *api.Client, name string) (string, error) { 75 if name == "" { 76 return "", fmt.Errorf("No name specified") 77 } 78 79 policies, _, err := client.ACL().PolicyList(nil) 80 if err != nil { 81 return "", err 82 } 83 84 for _, policy := range policies { 85 if policy.Name == name { 86 return policy.ID, nil 87 } 88 } 89 90 return "", fmt.Errorf("No such policy with name %s", name) 91} 92 93func GetRulesFromLegacyToken(client *api.Client, tokenID string, isSecret bool) (string, error) { 94 tokenID, err := GetTokenIDFromPartial(client, tokenID) 95 if err != nil { 96 return "", err 97 } 98 99 var token *api.ACLToken 100 if isSecret { 101 qopts := api.QueryOptions{ 102 Token: tokenID, 103 } 104 token, _, err = client.ACL().TokenReadSelf(&qopts) 105 } else { 106 token, _, err = client.ACL().TokenRead(tokenID, nil) 107 } 108 109 if err != nil { 110 return "", fmt.Errorf("Error reading token: %v", err) 111 } 112 113 if token == nil { 114 return "", fmt.Errorf("Token not found for ID") 115 } 116 117 if token.Rules == "" { 118 return "", fmt.Errorf("Token is not a legacy token with rules") 119 } 120 121 return token.Rules, nil 122} 123 124func GetRoleIDFromPartial(client *api.Client, partialID string) (string, error) { 125 // the full UUID string was given 126 if len(partialID) == 36 { 127 return partialID, nil 128 } 129 130 roles, _, err := client.ACL().RoleList(nil) 131 if err != nil { 132 return "", err 133 } 134 135 roleID := "" 136 for _, role := range roles { 137 if strings.HasPrefix(role.ID, partialID) { 138 if roleID != "" { 139 return "", fmt.Errorf("Partial role ID is not unique") 140 } 141 roleID = role.ID 142 } 143 } 144 145 if roleID == "" { 146 return "", fmt.Errorf("No such role ID with prefix: %s", partialID) 147 } 148 149 return roleID, nil 150} 151 152func GetRoleIDByName(client *api.Client, name string) (string, error) { 153 if name == "" { 154 return "", fmt.Errorf("No name specified") 155 } 156 157 roles, _, err := client.ACL().RoleList(nil) 158 if err != nil { 159 return "", err 160 } 161 162 for _, role := range roles { 163 if role.Name == name { 164 return role.ID, nil 165 } 166 } 167 168 return "", fmt.Errorf("No such role with name %s", name) 169} 170 171func GetBindingRuleIDFromPartial(client *api.Client, partialID string) (string, error) { 172 // the full UUID string was given 173 if len(partialID) == 36 { 174 return partialID, nil 175 } 176 177 rules, _, err := client.ACL().BindingRuleList("", nil) 178 if err != nil { 179 return "", err 180 } 181 182 ruleID := "" 183 for _, rule := range rules { 184 if strings.HasPrefix(rule.ID, partialID) { 185 if ruleID != "" { 186 return "", fmt.Errorf("Partial rule ID is not unique") 187 } 188 ruleID = rule.ID 189 } 190 } 191 192 if ruleID == "" { 193 return "", fmt.Errorf("No such rule ID with prefix: %s", partialID) 194 } 195 196 return ruleID, nil 197} 198 199func ExtractServiceIdentities(serviceIdents []string) ([]*api.ACLServiceIdentity, error) { 200 var out []*api.ACLServiceIdentity 201 for _, svcidRaw := range serviceIdents { 202 parts := strings.Split(svcidRaw, ":") 203 switch len(parts) { 204 case 2: 205 out = append(out, &api.ACLServiceIdentity{ 206 ServiceName: parts[0], 207 Datacenters: strings.Split(parts[1], ","), 208 }) 209 case 1: 210 out = append(out, &api.ACLServiceIdentity{ 211 ServiceName: parts[0], 212 }) 213 default: 214 return nil, fmt.Errorf("Malformed -service-identity argument: %q", svcidRaw) 215 } 216 } 217 return out, nil 218} 219 220func ExtractNodeIdentities(nodeIdents []string) ([]*api.ACLNodeIdentity, error) { 221 var out []*api.ACLNodeIdentity 222 for _, nodeidRaw := range nodeIdents { 223 parts := strings.Split(nodeidRaw, ":") 224 switch len(parts) { 225 case 2: 226 out = append(out, &api.ACLNodeIdentity{ 227 NodeName: parts[0], 228 Datacenter: parts[1], 229 }) 230 default: 231 return nil, fmt.Errorf("Malformed -node-identity argument: %q", nodeidRaw) 232 } 233 } 234 return out, nil 235} 236 237// TestKubernetesJWT_A is a valid service account jwt extracted from a minikube setup. 238// 239// { 240// "iss": "kubernetes/serviceaccount", 241// "kubernetes.io/serviceaccount/namespace": "default", 242// "kubernetes.io/serviceaccount/secret.name": "admin-token-qlz42", 243// "kubernetes.io/serviceaccount/service-account.name": "admin", 244// "kubernetes.io/serviceaccount/service-account.uid": "738bc251-6532-11e9-b67f-48e6c8b8ecb5", 245// "sub": "system:serviceaccount:default:admin" 246// } 247const TestKubernetesJWT_A = "eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImFkbWluLXRva2VuLXFsejQyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNzM4YmMyNTEtNjUzMi0xMWU5LWI2N2YtNDhlNmM4YjhlY2I1Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6YWRtaW4ifQ.ixMlnWrAG7NVuTTKu8cdcYfM7gweS3jlKaEsIBNGOVEjPE7rtXtgMkAwjQTdYR08_0QBjkgzy5fQC5ZNyglSwONJ-bPaXGvhoH1cTnRi1dz9H_63CfqOCvQP1sbdkMeRxNTGVAyWZT76rXoCUIfHP4LY2I8aab0KN9FTIcgZRF0XPTtT70UwGIrSmRpxW38zjiy2ymWL01cc5VWGhJqVysmWmYk3wNp0h5N57H_MOrz4apQR4pKaamzskzjLxO55gpbmZFC76qWuUdexAR7DT2fpbHLOw90atN_NlLMY-VrXyW3-Ei5EhYaVreMB9PSpKwkrA4jULITohV-sxpa1LA" 248 249// TestKubernetesJWT_B is a valid service account jwt extracted from a minikube setup. 250// 251// { 252// "iss": "kubernetes/serviceaccount", 253// "kubernetes.io/serviceaccount/namespace": "default", 254// "kubernetes.io/serviceaccount/secret.name": "demo-token-kmb9n", 255// "kubernetes.io/serviceaccount/service-account.name": "demo", 256// "kubernetes.io/serviceaccount/service-account.uid": "76091af4-4b56-11e9-ac4b-708b11801cbe", 257// "sub": "system:serviceaccount:default:demo" 258// } 259const TestKubernetesJWT_B = "eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlbW8tdG9rZW4ta21iOW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVtbyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6Ijc2MDkxYWY0LTRiNTYtMTFlOS1hYzRiLTcwOGIxMTgwMWNiZSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlbW8ifQ.ZiAHjijBAOsKdum0Aix6lgtkLkGo9_Tu87dWQ5Zfwnn3r2FejEWDAnftTft1MqqnMzivZ9Wyyki5ZjQRmTAtnMPJuHC-iivqY4Wh4S6QWCJ1SivBv5tMZR79t5t8mE7R1-OHwst46spru1pps9wt9jsA04d3LpV0eeKYgdPTVaQKklxTm397kIMUugA6yINIBQ3Rh8eQqBgNwEmL4iqyYubzHLVkGkoP9MJikFI05vfRiHtYr-piXz6JFDzXMQj9rW6xtMmrBSn79ChbyvC5nz-Nj2rJPnHsb_0rDUbmXY5PpnMhBpdSH-CbZ4j8jsiib6DtaGJhVZeEQ1GjsFAZwQ" 260