Skip to content

Commit 2a6694c

Browse files
authored
Merge pull request #204 from oracle/rbac-and-health
Cleaned-up RBAC roles, fixed HealthCheckHelper's security checks and optimized using rules review
2 parents cc5af9e + 6845c1d commit 2a6694c

File tree

13 files changed

+642
-202
lines changed

13 files changed

+642
-202
lines changed

kubernetes/internal/generate-security-policy.sh

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,11 @@ metadata:
9494
weblogic.operatorName: ${NAMESPACE}
9595
rules:
9696
- apiGroups: [""]
97-
resources: ["namespaces", "persistentvolumes"]
97+
resources: ["namespaces"]
9898
verbs: ["get", "list", "watch"]
99+
- apiGroups: [""]
100+
resources: ["persistentvolumes"]
101+
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
99102
- apiGroups: ["apiextensions.k8s.io"]
100103
resources: ["customresourcedefinitions"]
101104
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
@@ -108,6 +111,12 @@ rules:
108111
- apiGroups: ["extensions"]
109112
resources: ["ingresses"]
110113
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
114+
- apiGroups: ["authentication.k8s.io"]
115+
resources: ["tokenreviews"]
116+
verbs: ["create"]
117+
- apiGroups: ["authorization.k8s.io"]
118+
resources: ["selfsubjectaccessreviews", "localsubjectaccessreviews", "subjectaccessreviews", "selfsubjectrulesreviews"]
119+
verbs: ["create"]
111120
---
112121
kind: ClusterRole
113122
apiVersion: rbac.authorization.k8s.io/v1beta1
@@ -197,20 +206,23 @@ metadata:
197206
weblogic.operatorName: ${NAMESPACE}
198207
rules:
199208
- apiGroups: [""]
200-
resources: ["secrets", "persistentvolumeclaims"]
209+
resources: ["secrets"]
201210
verbs: ["get", "list", "watch"]
202211
- apiGroups: ["storage.k8s.io"]
203212
resources: ["storageclasses"]
204213
verbs: ["get", "list", "watch"]
205214
- apiGroups: [""]
206-
resources: ["services", "configmaps", "pods", "jobs", "events"]
215+
resources: ["services", "configmaps", "pods", "podtemplates", "events", "persistentvolumeclaims"]
207216
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
208217
- apiGroups: [""]
209218
resources: ["pods/logs"]
210219
verbs: ["get", "list"]
211220
- apiGroups: [""]
212221
resources: ["pods/exec"]
213222
verbs: ["create"]
223+
- apiGroups: ["batch"]
224+
resources: ["jobs", "cronjobs"]
225+
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
214226
- apiGroups: ["settings.k8s.io"]
215227
resources: ["podpresets"]
216228
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
@@ -253,4 +265,4 @@ EOF
253265
#
254266
echo "Create the WebLogic Operator Security configuration using kubectl as follows: kubectl create -f ${SCRIPT}"
255267
#
256-
echo "Ensure you start the API server with the --authorization-mode=RBAC option."
268+
echo "Ensure you start the API server with the --authorization-mode=RBAC option."

operator/src/main/java/oracle/kubernetes/operator/Main.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ private static void begin() {
220220
HealthCheckHelper healthCheck = new HealthCheckHelper(namespace, targetNamespaces);
221221
version = healthCheck.performK8sVersionCheck();
222222
healthCheck.performNonSecurityChecks();
223-
healthCheck.performSecurityChecks(serviceAccountName);
223+
healthCheck.performSecurityChecks(version);
224224
} catch (ApiException e) {
225225
LOGGER.warning(MessageKeys.EXCEPTION, e);
226226
}

operator/src/main/java/oracle/kubernetes/operator/helpers/AuthenticationProxy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public V1TokenReviewStatus check(String principal, String token) {
3636
try {
3737
boolean allowed = authorizationProxy.check(principal,
3838
AuthorizationProxy.Operation.create,
39-
AuthorizationProxy.Resource.tokenreviews,
39+
AuthorizationProxy.Resource.TOKENREVIEWS,
4040
null,
4141
AuthorizationProxy.Scope.cluster,
4242
null);

operator/src/main/java/oracle/kubernetes/operator/helpers/AuthorizationProxy.java

Lines changed: 96 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
import io.kubernetes.client.ApiException;
99
import io.kubernetes.client.models.V1ObjectMeta;
1010
import io.kubernetes.client.models.V1ResourceAttributes;
11+
import io.kubernetes.client.models.V1SelfSubjectAccessReview;
12+
import io.kubernetes.client.models.V1SelfSubjectAccessReviewSpec;
13+
import io.kubernetes.client.models.V1SelfSubjectRulesReview;
14+
import io.kubernetes.client.models.V1SelfSubjectRulesReviewSpec;
1115
import io.kubernetes.client.models.V1SubjectAccessReview;
1216
import io.kubernetes.client.models.V1SubjectAccessReviewSpec;
1317
import io.kubernetes.client.models.V1SubjectAccessReviewStatus;
@@ -37,18 +41,50 @@ public enum Operation {
3741
}
3842

3943
public enum Resource {
40-
pods,
41-
services,
42-
namespaces,
43-
customresources,
44-
customresourcedefinitions,
45-
domains,
46-
tokenreviews,
47-
networkpolicies,
48-
secrets,
49-
persistentvolumes,
50-
persistentvolumeclaims,
51-
ingresses
44+
CONFIGMAPS ("configmaps", ""),
45+
PODS ("pods", ""),
46+
LOGS ("pods", "logs", ""),
47+
EXEC ("pods", "exec", ""),
48+
PODTEMPLATES ("podtemplates", ""),
49+
EVENTS ("events", ""),
50+
SERVICES ("services", ""),
51+
NAMESPACES ("namespaces", ""),
52+
JOBS ("jobs", "batch"),
53+
CRONJOBS ("cronjobs", "batch"),
54+
CRDS ("customresourcedefinitions", "apiextensions.k8s.io"),
55+
DOMAINS ("domains", "weblogic.oracle"),
56+
DOMAINSTATUSS ("domains", "status", "weblogic.oracle"),
57+
SUBJECTACCESSREVIEWS ("subjectaccessreviews", "authorization.k8s.io"),
58+
SELFSUBJECTACCESSREVIEWS ("selfsubjectaccessreviews", "authorization.k8s.io"),
59+
LOCALSUBJECTACCESSREVIEWS ("localsubjectaccessreviews", "authorization.k8s.io"),
60+
SELFSUBJECTRULESREVIEWS ("selfsubjectrulesreviews", "authorization.k8s.io"),
61+
TOKENREVIEWS ("tokenreviews", "authentication.k8s.io"),
62+
SECRETS ("secrets", ""),
63+
PERSISTENTVOLUMES ("persistentvolumes", ""),
64+
PERSISTENTVOLUMECLAIMS ("persistentvolumeclaims", ""),
65+
STORAGECLASSES ("storageclasses", "storage.k8s.io"),
66+
PODPRESETS ("podpresets" , "settings.k8s.io"),
67+
INGRESSES ("ingresses", "extensions"),
68+
NETWORKPOLICIES ("networkpolicies", "extensions"),
69+
PODSECURITYPOLICIES ("podsecuritypolicies", "extensions");
70+
71+
private final String resource;
72+
private final String subResource;
73+
private final String apiGroup;
74+
75+
Resource(String resource, String apiGroup) {
76+
this(resource, "", apiGroup);
77+
}
78+
79+
Resource(String resource, String subResource, String apiGroup) {
80+
this.resource = resource;
81+
this.subResource = subResource;
82+
this.apiGroup = apiGroup;
83+
}
84+
85+
public String getResource() { return resource; }
86+
public String getSubResource() { return subResource; }
87+
public String getAPIGroup() { return apiGroup; }
5288
}
5389

5490
public enum Scope {
@@ -104,6 +140,24 @@ public boolean check(String principal, final List<String> groups, Operation oper
104140
return result;
105141
}
106142

143+
public boolean check(Operation operation, Resource resource, String resourceName, Scope scope, String namespaceName) {
144+
LOGGER.entering();
145+
V1SelfSubjectAccessReview subjectAccessReview = prepareSelfSubjectAccessReview(operation, resource, resourceName, scope, namespaceName);
146+
try {
147+
CallBuilderFactory factory = ContainerResolver.getInstance().getContainer().getSPI(CallBuilderFactory.class);
148+
subjectAccessReview = factory.create().createSelfSubjectAccessReview(subjectAccessReview);
149+
} catch (ApiException e) {
150+
LOGGER.severe(MessageKeys.APIEXCEPTION_FROM_SUBJECT_ACCESS_REVIEW, e);
151+
LOGGER.exiting(Boolean.FALSE);
152+
return Boolean.FALSE;
153+
154+
}
155+
V1SubjectAccessReviewStatus subjectAccessReviewStatus = subjectAccessReview.getStatus();
156+
Boolean result = subjectAccessReviewStatus.isAllowed();
157+
LOGGER.exiting(result);
158+
return result;
159+
}
160+
107161
/**
108162
* Prepares an instance of SubjectAccessReview and returns same.
109163
*
@@ -133,6 +187,21 @@ private V1SubjectAccessReview prepareSubjectAccessReview(String principal, final
133187
return subjectAccessReview;
134188
}
135189

190+
private V1SelfSubjectAccessReview prepareSelfSubjectAccessReview(Operation operation, Resource resource, String resourceName, Scope scope, String namespaceName) {
191+
LOGGER.entering();
192+
V1SelfSubjectAccessReviewSpec subjectAccessReviewSpec = new V1SelfSubjectAccessReviewSpec();
193+
194+
subjectAccessReviewSpec.setResourceAttributes(prepareResourceAttributes(operation, resource, resourceName, scope, namespaceName));
195+
196+
V1SelfSubjectAccessReview subjectAccessReview = new V1SelfSubjectAccessReview();
197+
subjectAccessReview.setApiVersion("authorization.k8s.io/v1");
198+
subjectAccessReview.setKind("SelfSubjectAccessReview");
199+
subjectAccessReview.setMetadata(new V1ObjectMeta());
200+
subjectAccessReview.setSpec(subjectAccessReviewSpec);
201+
LOGGER.exiting(subjectAccessReview);
202+
return subjectAccessReview;
203+
}
204+
136205
/**
137206
* Prepares an instance of ResourceAttributes and returns same.
138207
*
@@ -150,12 +219,9 @@ private V1ResourceAttributes prepareResourceAttributes(Operation operation, Reso
150219
resourceAttributes.setVerb(operation.toString());
151220
}
152221
if (null != resource) {
153-
resourceAttributes.setResource(resource.toString());
154-
}
155-
156-
String apiGroup = getApiGroup(resource);
157-
if (apiGroup != null) {
158-
resourceAttributes.setGroup(apiGroup);
222+
resourceAttributes.setResource(resource.resource);
223+
resourceAttributes.setSubresource(resource.subResource);
224+
resourceAttributes.setGroup(resource.apiGroup);
159225
}
160226

161227
if (null != resourceName) {
@@ -168,25 +234,18 @@ private V1ResourceAttributes prepareResourceAttributes(Operation operation, Reso
168234
LOGGER.exiting(resourceAttributes);
169235
return resourceAttributes;
170236
}
171-
172-
private String getApiGroup(Resource resource) {
173-
if (resource == Resource.domains) {
174-
return "weblogic.oracle";
175-
}
176-
177-
if (resource == Resource.customresourcedefinitions) {
178-
return "apiextensions.k8s.io";
179-
}
180-
181-
if (resource == Resource.tokenreviews) {
182-
return "authentication.k8s.io";
183-
}
184-
185-
if (resource == Resource.ingresses) {
186-
return "extensions";
237+
238+
public V1SelfSubjectRulesReview review(String namespace) {
239+
V1SelfSubjectRulesReview subjectRulesReview = new V1SelfSubjectRulesReview();
240+
V1SelfSubjectRulesReviewSpec spec = new V1SelfSubjectRulesReviewSpec();
241+
spec.setNamespace(namespace);
242+
subjectRulesReview.setSpec(spec);
243+
CallBuilderFactory factory = ContainerResolver.getInstance().getContainer().getSPI(CallBuilderFactory.class);
244+
try {
245+
return factory.create().createSelfSubjectRulesReview(subjectRulesReview);
246+
} catch (ApiException e) {
247+
LOGGER.warning(MessageKeys.EXCEPTION, e);
248+
return null;
187249
}
188-
189-
// TODO - do we need to specify the api group for any of the other Resource values?
190-
return null;
191250
}
192251
}

operator/src/main/java/oracle/kubernetes/operator/helpers/CallBuilder.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import io.kubernetes.client.models.V1Pod;
3737
import io.kubernetes.client.models.V1PodList;
3838
import io.kubernetes.client.models.V1Secret;
39+
import io.kubernetes.client.models.V1SelfSubjectAccessReview;
40+
import io.kubernetes.client.models.V1SelfSubjectRulesReview;
3941
import io.kubernetes.client.models.V1Service;
4042
import io.kubernetes.client.models.V1ServiceList;
4143
import io.kubernetes.client.models.V1Status;
@@ -1384,6 +1386,76 @@ public Step createSubjectAccessReviewAsync(V1SubjectAccessReview body, ResponseS
13841386
return createRequestAsync(responseStep, new RequestParams("createSubjectAccessReview", null, null, body), CREATE_SUBJECTACCESSREVIEW);
13851387
}
13861388

1389+
/* Self Subject Access Review */
1390+
1391+
/**
1392+
* Create self subject access review
1393+
* @param body Body
1394+
* @return Created self subject access review
1395+
* @throws ApiException API Exception
1396+
*/
1397+
public V1SelfSubjectAccessReview createSelfSubjectAccessReview(V1SelfSubjectAccessReview body) throws ApiException {
1398+
ApiClient client = helper.take();
1399+
try {
1400+
return new AuthorizationV1Api(client).createSelfSubjectAccessReview(body, pretty);
1401+
} finally {
1402+
helper.recycle(client);
1403+
}
1404+
}
1405+
1406+
private com.squareup.okhttp.Call createSelfSubjectAccessReviewAsync(ApiClient client, V1SelfSubjectAccessReview body, ApiCallback<V1SelfSubjectAccessReview> callback) throws ApiException {
1407+
return new AuthorizationV1Api(client).createSelfSubjectAccessReviewAsync(body, pretty, callback);
1408+
}
1409+
1410+
private final CallFactory<V1SelfSubjectAccessReview> CREATE_SELFSUBJECTACCESSREVIEW = (requestParams, usage, cont, callback) -> {
1411+
return createSelfSubjectAccessReviewAsync(usage, (V1SelfSubjectAccessReview) requestParams.body, callback);
1412+
};
1413+
1414+
/**
1415+
* Asynchronous step for creating self subject access review
1416+
* @param body Body
1417+
* @param responseStep Response step for when call completes
1418+
* @return Asynchronous step
1419+
*/
1420+
public Step createSelfSubjectAccessReviewAsync(V1SelfSubjectAccessReview body, ResponseStep<V1SelfSubjectAccessReview> responseStep) {
1421+
return createRequestAsync(responseStep, new RequestParams("createSelfSubjectAccessReview", null, null, body), CREATE_SELFSUBJECTACCESSREVIEW);
1422+
}
1423+
1424+
/* Self Subject Rules Review */
1425+
1426+
/**
1427+
* Create self subject rules review
1428+
* @param body Body
1429+
* @return Created self subject rules review
1430+
* @throws ApiException API Exception
1431+
*/
1432+
public V1SelfSubjectRulesReview createSelfSubjectRulesReview(V1SelfSubjectRulesReview body) throws ApiException {
1433+
ApiClient client = helper.take();
1434+
try {
1435+
return new AuthorizationV1Api(client).createSelfSubjectRulesReview(body, pretty);
1436+
} finally {
1437+
helper.recycle(client);
1438+
}
1439+
}
1440+
1441+
private com.squareup.okhttp.Call createSelfSubjectRulesReviewAsync(ApiClient client, V1SelfSubjectRulesReview body, ApiCallback<V1SelfSubjectRulesReview> callback) throws ApiException {
1442+
return new AuthorizationV1Api(client).createSelfSubjectRulesReviewAsync(body, pretty, callback);
1443+
}
1444+
1445+
private final CallFactory<V1SelfSubjectRulesReview> CREATE_SELFSUBJECTRULESREVIEW = (requestParams, usage, cont, callback) -> {
1446+
return createSelfSubjectRulesReviewAsync(usage, (V1SelfSubjectRulesReview) requestParams.body, callback);
1447+
};
1448+
1449+
/**
1450+
* Asynchronous step for creating self subject rules review
1451+
* @param body Body
1452+
* @param responseStep Response step for when call completes
1453+
* @return Asynchronous step
1454+
*/
1455+
public Step createSelfSubjectRulesReviewAsync(V1SelfSubjectRulesReview body, ResponseStep<V1SelfSubjectRulesReview> responseStep) {
1456+
return createRequestAsync(responseStep, new RequestParams("createSelfSubjectRulesReview", null, null, body), CREATE_SELFSUBJECTRULESREVIEW);
1457+
}
1458+
13871459
/* Token Review */
13881460

13891461
/**
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2018, Oracle Corporation and/or its affiliates. All rights reserved.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
3+
4+
package oracle.kubernetes.operator.helpers;
5+
6+
import java.util.function.Supplier;
7+
8+
import io.kubernetes.client.ApiClient;
9+
10+
public interface ClientFactory extends Supplier<ApiClient> {
11+
12+
}

0 commit comments

Comments
 (0)