1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package kcpclient
import (
"encoding/base32"
"errors"
"fmt"
"regexp"
"strings"
kcpv1alpha1 "github.com/kcp-dev/sdk/apis/tenancy/v1alpha1"
"github.com/johnandersen777/socialweb-computer-kcp/internal/contract/clusterhome"
)
const (
fieldManagerClusterProvider = "socialweb.computer/clusterprovider"
fieldManagerGateway = "socialweb.computer/gateway"
fieldManagerRevocation = "socialweb.computer/revocation"
)
func IdentityRecordName(did string) string {
return clusterhome.AccountHash(did)
}
const TenantNamespace = "users"
func ServiceAccountName(did string) string {
return "did-" + strings.ToLower(base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString([]byte(did)))
}
const GrantOwnerPlaceholder = "__SOCIALWEB_OWNER_SERVICE_ACCOUNT__"
const GrantESOUserPlaceholder = "__SOCIALWEB_ESO_USER__"
var grantUsername = regexp.MustCompile(`^[a-z0-9]([a-z0-9:.-]*[a-z0-9])?$`)
type GrantScope struct {
OwnerDID string
ESOUser string
}
func RenderTenantGrant(doc string, scope GrantScope) (string, error) {
if scope.OwnerDID == "" {
return "", errors.New(
"kcpclient: the tenant grant needs the owning DID: every name it scopes is derived from it, " +
"and a grant rendered without one would be scoped to a name nothing owns")
}
if scope.ESOUser == "" {
return "", errors.New(
"kcpclient: the tenant grant needs the username the External Secrets controller " +
"authenticates as: the policy admits that controller, and only it besides the " +
"provisioning admin, to write the vault-backed Secrets in the tenant namespace, so a " +
"grant rendered without it denies every sync, which reads as a broken ExternalSecret " +
"rather than as a grant that does not name it")
}
if !grantUsername.MatchString(scope.ESOUser) {
return "", fmt.Errorf(
"kcpclient: the External Secrets username %q is not of the form %s, and the policy "+
"compares it inside a CEL string literal, where a quote or a backslash would end it",
scope.ESOUser, grantUsername)
}
for _, p := range []struct{ name, placeholder string }{
{"the owning DID", GrantOwnerPlaceholder},
{"the External Secrets username", GrantESOUserPlaceholder},
} {
if !strings.Contains(doc, p.placeholder) {
return "", fmt.Errorf(
"kcpclient: the tenant grant carries no placeholder for %s (%s), so rendering it would "+
"apply a grant scoped to whatever is written in the file rather than to the value "+
"this renderer was handed", p.name, p.placeholder)
}
}
rendered := strings.ReplaceAll(doc, GrantOwnerPlaceholder, ServiceAccountName(scope.OwnerDID))
return strings.ReplaceAll(rendered, GrantESOUserPlaceholder, scope.ESOUser), nil
}
const (
AccountWorkspaceType kcpv1alpha1.WorkspaceTypeName = "account"
HomeWorkspaceType kcpv1alpha1.WorkspaceTypeName = "cluster"
)