Browse code

Update registry policy

Add subresource imagestreams/layers for allowing push/pull access to the
registry.

Update registry authentication code to use imagestreams/layers.

Remove use of user's token for registry<->OpenShift interactions except
for when auto-provisioning an image stream. Otherwise, use the
registry's credentials when interacting with OpenShift. The user's
access is checked via a SubjectAccessReview check during authorization
of the request.

Andy Goldstein authored on 2015/06/02 05:18:34
Showing 3 changed files
... ...
@@ -135,7 +135,7 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole {
135 135
 			Rules: []authorizationapi.PolicyRule{
136 136
 				{
137 137
 					Verbs:     util.NewStringSet("get"),
138
-					Resources: util.NewStringSet("imagestreams"),
138
+					Resources: util.NewStringSet("imagestreams/layers"),
139 139
 				},
140 140
 			},
141 141
 		},
... ...
@@ -146,7 +146,7 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole {
146 146
 			Rules: []authorizationapi.PolicyRule{
147 147
 				{
148 148
 					Verbs:     util.NewStringSet("get", "update"),
149
-					Resources: util.NewStringSet("imagestreams"),
149
+					Resources: util.NewStringSet("imagestreams/layers"),
150 150
 				},
151 151
 			},
152 152
 		},
... ...
@@ -221,13 +221,12 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole {
221 221
 					Resources: util.NewStringSet("imagestreamimages", "imagestreamtags", "imagestreams"),
222 222
 				},
223 223
 				{
224
-					// TODO: remove "create" once we re-enable user authentication in the registry
225
-					Verbs:     util.NewStringSet("create", "update"),
224
+					Verbs:     util.NewStringSet("update"),
226 225
 					Resources: util.NewStringSet("imagestreams"),
227 226
 				},
228 227
 				{
229 228
 					Verbs:     util.NewStringSet("create"),
230
-					Resources: util.NewStringSet("imagerepositorymappings", "imagestreammappings"),
229
+					Resources: util.NewStringSet("imagestreammappings"),
231 230
 				},
232 231
 			},
233 232
 		},
... ...
@@ -90,6 +90,7 @@ func (ac *AccessController) Authorized(ctx context.Context, accessRecords ...reg
90 90
 		return nil, err
91 91
 	}
92 92
 
93
+	// TODO try to find a better way to handle this
93 94
 	if req.URL.Path == "/healthz" {
94 95
 		return ctx, nil
95 96
 	}
... ...
@@ -109,6 +110,7 @@ func (ac *AccessController) Authorized(ctx context.Context, accessRecords ...reg
109 109
 		challenge.err = ErrTokenInvalid
110 110
 		return nil, challenge
111 111
 	}
112
+
112 113
 	osAuthParts := strings.SplitN(string(payload), ":", 2)
113 114
 	if len(osAuthParts) != 2 {
114 115
 		challenge.err = ErrOpenShiftTokenRequired
... ...
@@ -131,7 +133,7 @@ func (ac *AccessController) Authorized(ctx context.Context, accessRecords ...reg
131 131
 	}
132 132
 
133 133
 	for _, access := range accessRecords {
134
-		log.Debugf("%s:%s:%s", access.Resource.Type, access.Resource.Name, access.Action)
134
+		log.Debugf("OpenShift auth: checking for access to %s:%s:%s", access.Resource.Type, access.Resource.Name, access.Action)
135 135
 
136 136
 		switch access.Resource.Type {
137 137
 		case "repository":
... ...
@@ -166,7 +168,7 @@ func (ac *AccessController) Authorized(ctx context.Context, accessRecords ...reg
166 166
 					return nil, challenge
167 167
 				}
168 168
 
169
-				return WithUserClient(ctx, client), nil
169
+				return ctx, nil
170 170
 			default:
171 171
 				challenge.err = fmt.Errorf("Unknown action: %s", access.Action)
172 172
 				return nil, challenge
... ...
@@ -188,7 +190,7 @@ func verifyOpenShiftUser(client *client.Client) error {
188 188
 func verifyImageStreamAccess(namespace, imageRepo, verb string, client *client.Client) error {
189 189
 	sar := authorizationapi.SubjectAccessReview{
190 190
 		Verb:         verb,
191
-		Resource:     "imageStreams",
191
+		Resource:     "imagestreams/layers",
192 192
 		ResourceName: imageRepo,
193 193
 	}
194 194
 	response, err := client.SubjectAccessReviews(namespace).Create(&sar)
... ...
@@ -100,13 +100,14 @@ func (r *repository) ExistsByTag(ctx context.Context, tag string) (bool, error)
100 100
 
101 101
 // Get retrieves the manifest with digest `dgst`.
102 102
 func (r *repository) Get(ctx context.Context, dgst digest.Digest) (*manifest.SignedManifest, error) {
103
-	_, err := r.getImageStreamImage(ctx, dgst)
104
-	if err != nil {
103
+	if _, err := r.getImageStreamImage(ctx, dgst); err != nil {
104
+		log.Errorf("Error retrieving ImageStreamImage %s/%s@%s: %v", r.namespace, r.name, dgst.String(), err)
105 105
 		return nil, err
106 106
 	}
107
-	// TODO: we already fetched it above
107
+
108 108
 	image, err := r.getImage(dgst)
109 109
 	if err != nil {
110
+		log.Errorf("Error retrieving image %s: %v", dgst.String(), err)
110 111
 		return nil, err
111 112
 	}
112 113
 
... ...
@@ -233,16 +234,10 @@ func (r *repository) Delete(ctx context.Context, dgst digest.Digest) error {
233 233
 
234 234
 // getImageStream retrieves the ImageStream for r.
235 235
 func (r *repository) getImageStream(ctx context.Context) (*imageapi.ImageStream, error) {
236
-	client, ok := UserClientFrom(ctx)
237
-	if !ok {
238
-		return nil, fmt.Errorf("error retrieving ImageStream: OpenShift user client unavailable")
239
-	}
240
-	return client.ImageStreams(r.namespace).Get(r.name)
236
+	return r.registryClient.ImageStreams(r.namespace).Get(r.name)
241 237
 }
242 238
 
243
-// getImage retrieves the Image with digest `dgst`. This uses the registry's
244
-// credentials and should ONLY be called after verifying the user has access
245
-// to the image stream the imgae belongs to.
239
+// getImage retrieves the Image with digest `dgst`.
246 240
 func (r *repository) getImage(dgst digest.Digest) (*imageapi.Image, error) {
247 241
 	return r.registryClient.Images().Get(dgst.String())
248 242
 }
... ...
@@ -250,21 +245,13 @@ func (r *repository) getImage(dgst digest.Digest) (*imageapi.Image, error) {
250 250
 // getImageStreamTag retrieves the Image with tag `tag` for the ImageStream
251 251
 // associated with r.
252 252
 func (r *repository) getImageStreamTag(ctx context.Context, tag string) (*imageapi.ImageStreamTag, error) {
253
-	client, ok := UserClientFrom(ctx)
254
-	if !ok {
255
-		return nil, fmt.Errorf("error retrieving ImageStreamTag: OpenShift user client unavailable")
256
-	}
257
-	return client.ImageStreamTags(r.namespace).Get(r.name, tag)
253
+	return r.registryClient.ImageStreamTags(r.namespace).Get(r.name, tag)
258 254
 }
259 255
 
260 256
 // getImageStreamImage retrieves the Image with digest `dgst` for the ImageStream
261
-// associated with r. This ensures the user has access to the image.
257
+// associated with r. This ensures the image belongs to the image stream.
262 258
 func (r *repository) getImageStreamImage(ctx context.Context, dgst digest.Digest) (*imageapi.ImageStreamImage, error) {
263
-	client, ok := UserClientFrom(ctx)
264
-	if !ok {
265
-		return nil, fmt.Errorf("error retrieving ImageStreamImage: OpenShift user client unavailable")
266
-	}
267
-	return client.ImageStreamImages(r.namespace).Get(r.name, dgst.String())
259
+	return r.registryClient.ImageStreamImages(r.namespace).Get(r.name, dgst.String())
268 260
 }
269 261
 
270 262
 // manifestFromImage converts an Image to a SignedManifest.