Skip to content

Commit bc3e7b1

Browse files
authored
feat(grafanaplane/cloud): add opinionated AccessPolicy and AccessPolicyToken resources (#35)
1 parent 3943120 commit bc3e7b1

2 files changed

Lines changed: 294 additions & 3 deletions

File tree

docs/cloud.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@
44

55
## Index
66

7+
* [`obj accessPolicy`](#obj-accesspolicy)
8+
* [`fn addToken(secretName, secretNamespace)`](#fn-accesspolicyaddtoken)
9+
* [`fn forOrg(name, namespace, scopes)`](#fn-accesspolicyfororg)
10+
* [`fn forStackResource(stackResource, namespace)`](#fn-accesspolicyforstackresource)
11+
* [`fn new(name, namespace, scopes)`](#fn-accesspolicynew)
12+
* [`fn withStack(id, region)`](#fn-accesspolicywithstack)
13+
* [`obj accessPolicyToken`](#obj-accesspolicytoken)
14+
* [`fn forAccessPolicyResource(accessPolicyResource)`](#fn-accesspolicytokenforaccesspolicyresource)
15+
* [`fn new(secretName, secretNamespace)`](#fn-accesspolicytokennew)
16+
* [`fn withAccessPolicyId(id)`](#fn-accesspolicytokenwithaccesspolicyid)
717
* [`obj stack`](#obj-stack)
818
* [`fn new(name, namespace, cloudProviderConfigName, secretName="<name>-providerconfig-token")`](#fn-stacknew)
919
* [`obj stackServiceAccount`](#obj-stackserviceaccount)
@@ -13,6 +23,131 @@
1323

1424
## Fields
1525

26+
### obj accessPolicy
27+
28+
29+
#### fn accessPolicy.addToken
30+
31+
```jsonnet
32+
accessPolicy.addToken(secretName, secretNamespace)
33+
```
34+
35+
PARAMETERS:
36+
37+
* **secretName** (`string`)
38+
* **secretNamespace** (`string`)
39+
40+
`addToken` creates a new Access Policy Token under this Access Policy, the token will be available in the provider secret.
41+
42+
#### fn accessPolicy.forOrg
43+
44+
```jsonnet
45+
accessPolicy.forOrg(name, namespace, scopes)
46+
```
47+
48+
PARAMETERS:
49+
50+
* **name** (`string`)
51+
* **namespace** (`string`)
52+
* **scopes** (`array`)
53+
54+
`forOrg` configures the `realm` to an org `slug`.
55+
56+
#### fn accessPolicy.forStackResource
57+
58+
```jsonnet
59+
accessPolicy.forStackResource(stackResource, namespace)
60+
```
61+
62+
PARAMETERS:
63+
64+
* **stackResource** (`string`)
65+
* **namespace** (`string`)
66+
67+
`forStackResource` configures the `realm` for a `stackResource`.
68+
69+
The `stackResource` is in the `stack` key returned by `cloud.stack.new()`.
70+
71+
#### fn accessPolicy.new
72+
73+
```jsonnet
74+
accessPolicy.new(name, namespace, scopes)
75+
```
76+
77+
PARAMETERS:
78+
79+
* **name** (`string`)
80+
* **namespace** (`string`)
81+
* **scopes** (`array`)
82+
83+
`new` creates a new Access Policy.
84+
85+
For `scopes`, see https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/#scopes for possible values.
86+
87+
A valid Access Policy also needs a `realm`, use one of the following functions:
88+
- `withStack`: reference a stack by its identifier (id).
89+
- `forStackResource`: reference a stack by a Crossplane resource.
90+
- `forOrg`: set realm to org level
91+
92+
#### fn accessPolicy.withStack
93+
94+
```jsonnet
95+
accessPolicy.withStack(id, region)
96+
```
97+
98+
PARAMETERS:
99+
100+
* **id** (`string`)
101+
* **region** (`string`)
102+
103+
`withStack` configures the `realm` to a stack `id`.
104+
### obj accessPolicyToken
105+
106+
107+
#### fn accessPolicyToken.forAccessPolicyResource
108+
109+
```jsonnet
110+
accessPolicyToken.forAccessPolicyResource(accessPolicyResource)
111+
```
112+
113+
PARAMETERS:
114+
115+
* **accessPolicyResource** (`object`)
116+
117+
`forAccessPolicyResource` configures the Access Policy` for a `accessPolicyResource`.
118+
119+
The `accessPolicyResource` is in the `accessPolicy` key returned by `cloud.accessPolicy.new()`.
120+
121+
#### fn accessPolicyToken.new
122+
123+
```jsonnet
124+
accessPolicyToken.new(secretName, secretNamespace)
125+
```
126+
127+
PARAMETERS:
128+
129+
* **secretName** (`string`)
130+
* **secretNamespace** (`string`)
131+
132+
`new` creates a new Access Policy Token.
133+
134+
Tip: use `accessPolicy.addToken()` to automatically link the token to the right Access Policy.
135+
136+
A valid Access Policy Token also needs an Access Policy, use one of the following functions:
137+
- `withAccessPolicyId`: reference a policy by its identifier (id)
138+
- `forAccessPolicyResource`: reference a policy by a Crossplane resource.
139+
140+
#### fn accessPolicyToken.withAccessPolicyId
141+
142+
```jsonnet
143+
accessPolicyToken.withAccessPolicyId(id)
144+
```
145+
146+
PARAMETERS:
147+
148+
* **id** (`string`)
149+
150+
`withAccessPolicyId` configures the Access Policy to a policy `id`.
16151
### obj stack
17152

18153

grafanaplane/cloud.libsonnet

Lines changed: 159 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ local raw = import './zz/main.libsonnet';
77
{
88
'#': d.package.newSub('cloud', ''),
99

10-
local this = self,
10+
local root = self,
1111
local validStackSlug(slug) =
1212
xtd.ascii.isLower(slug[0])
1313
&& std.all(
@@ -39,8 +39,8 @@ local raw = import './zz/main.libsonnet';
3939
+ raw.cloud.v1alpha1.stack.spec.parameters.forProvider.withName(name)
4040
+ raw.cloud.v1alpha1.stack.spec.parameters.forProvider.withSlug(name),
4141

42-
serviceAccount: this.stackServiceAccount.fromStackResource(self.stack, namespace),
43-
token: this.stackServiceAccountToken.fromStackServiceAccountResource(self.serviceAccount, namespace, secretName),
42+
serviceAccount: root.stackServiceAccount.fromStackResource(self.stack, namespace),
43+
token: root.stackServiceAccountToken.fromStackServiceAccountResource(self.serviceAccount, namespace, secretName),
4444
grafanaProviderConfig: global.providerConfig.new(name + '-grafana', secretName, namespace, 'instanceCredentials'),
4545
},
4646
},
@@ -91,4 +91,160 @@ local raw = import './zz/main.libsonnet';
9191
stackServiceAccountResource.spec.parameters.providerConfigRef
9292
),
9393
},
94+
95+
accessPolicy: {
96+
local forProvider = raw.cloud.v1alpha1.accessPolicy.spec.parameters.forProvider,
97+
98+
'#new': d.func.new(
99+
|||
100+
`new` creates a new Access Policy.
101+
102+
For `scopes`, see https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/#scopes for possible values.
103+
104+
A valid Access Policy also needs a `realm`, use one of the following functions:
105+
- `withStack`: reference a stack by its identifier (id).
106+
- `forStackResource`: reference a stack by a Crossplane resource.
107+
- `forOrg`: set realm to org level
108+
|||,
109+
[
110+
d.argument.new('name', d.T.string),
111+
d.argument.new('namespace', d.T.string),
112+
d.argument.new('scopes', d.T.array),
113+
]
114+
),
115+
new(name, namespace, scopes): {
116+
accessPolicy:
117+
raw.cloud.v1alpha1.accessPolicy.new(name)
118+
+ raw.cloud.v1alpha1.accessPolicy.metadata.withNamespace(namespace)
119+
+ forProvider.withName(name)
120+
+ forProvider.withScopes(scopes),
121+
},
122+
123+
'#withStack': d.func.new(
124+
'`withStack` configures the `realm` to a stack `id`.',
125+
[
126+
d.argument.new('id', d.T.string),
127+
d.argument.new('region', d.T.string),
128+
]
129+
),
130+
withStack(id, region): {
131+
accessPolicy+:
132+
forProvider.withRealm(
133+
forProvider.realm.withType('stack')
134+
+ forProvider.realm.withIdentifier(id)
135+
)
136+
+ forProvider.withRegion(region),
137+
},
138+
139+
'#forStackResource': d.func.new(
140+
|||
141+
`forStackResource` configures the `realm` for a `stackResource`.
142+
143+
The `stackResource` is in the `stack` key returned by `cloud.stack.new()`.
144+
|||,
145+
[
146+
d.argument.new('stackResource', d.T.string),
147+
d.argument.new('namespace', d.T.string),
148+
]
149+
),
150+
forStackResource(stackResource, namespace=stackResource.metadata.namespace): {
151+
accessPolicy+:
152+
forProvider.withRealm(
153+
forProvider.realm.withType('stack')
154+
+ forProvider.realm.stackSelector.withMatchLabels({
155+
'crossplane.io/claim-name': stackResource.metadata.name,
156+
'crossplane.io/claim-namespace': namespace,
157+
})
158+
)
159+
// region is a required attribute,
160+
// this'll require that `stackResource` has regionSlug configured
161+
+ forProvider.withRegion(stackResource.spec.parameters.forProvider.regionSlug),
162+
},
163+
164+
'#forOrg': d.func.new(
165+
|||
166+
`forOrg` configures the `realm` to an org `slug`.
167+
|||,
168+
[
169+
d.argument.new('name', d.T.string),
170+
d.argument.new('namespace', d.T.string),
171+
d.argument.new('scopes', d.T.array),
172+
]
173+
),
174+
forOrg(slug, region='prod-us-east-0'): {
175+
accessPolicy+:
176+
forProvider.withRealm(
177+
forProvider.realm.withType('org')
178+
+ forProvider.realm.withIdentifier(slug)
179+
)
180+
// region is a required attribute,
181+
// it is a bit unclear what this needs to be for an 'org' policy
182+
+ forProvider.withRegion(region),
183+
},
184+
185+
'#addToken': d.func.new(
186+
|||
187+
`addToken` creates a new Access Policy Token under this Access Policy, the token will be available in the provider secret.
188+
|||,
189+
[
190+
d.argument.new('secretName', d.T.string),
191+
d.argument.new('secretNamespace', d.T.string),
192+
]
193+
),
194+
addToken(secretName, secretNamespace): {
195+
local this = self,
196+
tokens+: {
197+
[secretName]:
198+
root.accessPolicyToken.new(secretName, secretNamespace)
199+
+ root.accessPolicyToken.forAccessPolicyResource(this.accessPolicy),
200+
},
201+
},
202+
},
203+
204+
accessPolicyToken: {
205+
local parameters = raw.cloud.v1alpha1.accessPolicyToken.spec.parameters,
206+
207+
'#new': d.func.new(
208+
|||
209+
`new` creates a new Access Policy Token.
210+
211+
Tip: use `accessPolicy.addToken()` to automatically link the token to the right Access Policy.
212+
213+
A valid Access Policy Token also needs an Access Policy, use one of the following functions:
214+
- `withAccessPolicyId`: reference a policy by its identifier (id)
215+
- `forAccessPolicyResource`: reference a policy by a Crossplane resource.
216+
|||,
217+
[
218+
d.argument.new('secretName', d.T.string),
219+
d.argument.new('secretNamespace', d.T.string),
220+
]
221+
),
222+
new(secretName, secretNamespace):
223+
raw.cloud.v1alpha1.accessPolicyToken.new(secretName)
224+
+ parameters.forProvider.withName(secretName)
225+
+ parameters.writeConnectionSecretToRef.withName(secretName)
226+
+ parameters.writeConnectionSecretToRef.withNamespace(secretNamespace),
227+
228+
'#withAccessPolicyId': d.func.new(
229+
'`withAccessPolicyId` configures the Access Policy to a policy `id`.',
230+
[d.argument.new('id', d.T.string)]
231+
),
232+
withAccessPolicyId(id):
233+
parameters.forProvider.withAccessPolicyId(id),
234+
235+
'#forAccessPolicyResource': d.func.new(
236+
|||
237+
`forAccessPolicyResource` configures the Access Policy` for a `accessPolicyResource`.
238+
239+
The `accessPolicyResource` is in the `accessPolicy` key returned by `cloud.accessPolicy.new()`.
240+
|||,
241+
[d.argument.new('accessPolicyResource', d.T.object)]
242+
),
243+
forAccessPolicyResource(accessPolicyResource):
244+
parameters.forProvider.withRegion(accessPolicyResource.spec.parameters.forProvider.region)
245+
+ parameters.forProvider.accessPolicySelector.withMatchLabels({
246+
'crossplane.io/claim-name': accessPolicyResource.metadata.name,
247+
'crossplane.io/claim-namespace': accessPolicyResource.metadata.namespace,
248+
}),
249+
},
94250
}

0 commit comments

Comments
 (0)