converging on proper rotation
This commit is contained in:
parent
aaf9e83278
commit
f406942984
4 changed files with 101 additions and 67 deletions
|
@ -514,7 +514,7 @@ class SuperUserServiceKeyManagement(ApiResource):
|
|||
@require_scope(scopes.SUPERUSER)
|
||||
def get(self):
|
||||
if SuperUserPermission().can():
|
||||
return jsonify(list(model.service_keys.get_service_keys(False)))
|
||||
return jsonify(model.service_keys.get_keys())
|
||||
abort(403)
|
||||
|
||||
@verify_not_prod
|
||||
|
@ -538,7 +538,7 @@ class SuperUserServiceKeyManagement(ApiResource):
|
|||
metadata.update({
|
||||
'created_by': 'Quay SuperUser Panel',
|
||||
'creator': user.username,
|
||||
'superuser ip': request.remote_addr,
|
||||
'ip': request.remote_addr,
|
||||
})
|
||||
|
||||
private_key = RSA.generate(2048)
|
||||
|
@ -551,7 +551,8 @@ class SuperUserServiceKeyManagement(ApiResource):
|
|||
metadata, expiration_date)
|
||||
model.service_keys.approve_service_key(kid, user, ServiceKeyApprovalType.SUPERUSER)
|
||||
|
||||
return jsonify({'private_key': private_key.exportKey('PEM')})
|
||||
return jsonify({'public_key': private_key.publickey().exportKey('PEM'),
|
||||
'private_key': private_key.exportKey('PEM')})
|
||||
|
||||
abort(403)
|
||||
|
||||
|
@ -559,7 +560,7 @@ class SuperUserServiceKeyManagement(ApiResource):
|
|||
@resource('/v1/superuser/keys/<kid>')
|
||||
@path_param('kid', 'The unique identifier for a service key')
|
||||
@show_if(features.SUPER_USERS)
|
||||
class SuperUserServiceKeyManagement(ApiResource):
|
||||
class SuperUserServiceKeyUpdater(ApiResource):
|
||||
""" Resource for managing service keys. """
|
||||
schemas = {
|
||||
'PutServiceKey': {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import json
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import jwt
|
||||
|
@ -46,20 +48,16 @@ def _validate_jwt(encoded_jwt, jwk, service):
|
|||
abort(400)
|
||||
|
||||
|
||||
def _signer_jwk(encoded_jwt, jwk, kid):
|
||||
def _signer_kid(encoded_jwt):
|
||||
decoded_jwt = jwt.decode(encoded_jwt, verify=False)
|
||||
return decoded_jwt.get('signer_kid', None)
|
||||
|
||||
signer_kid = decoded_jwt.get('signer_kid', '')
|
||||
# If we already have our own JWK and it's the signer, short-circuit.
|
||||
if (signer_kid == kid or signer_kid == '') and jwk is not None:
|
||||
return jwk
|
||||
else:
|
||||
try:
|
||||
service_key = data.model.service_keys.get_service_key(signer_kid)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
abort(404)
|
||||
|
||||
return service_key.jwk
|
||||
def _signer_key(signer_kid):
|
||||
try:
|
||||
return data.model.service_keys.get_service_key(signer_kid)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
abort(403)
|
||||
|
||||
|
||||
@key_server.route('/services/<service>/keys', methods=['GET'])
|
||||
|
@ -88,25 +86,31 @@ def put_service_keys(service, kid):
|
|||
except ValueError:
|
||||
abort(400)
|
||||
|
||||
_validate_jwk(jwk, kid)
|
||||
|
||||
encoded_jwt = request.headers.get(JWT_HEADER_NAME, None)
|
||||
if not encoded_jwt:
|
||||
abort(400)
|
||||
|
||||
signer_jwk = _signer_jwk(encoded_jwt, jwk, kid)
|
||||
_validate_jwt(encoded_jwt, signer_jwk, service)
|
||||
_validate_jwk(jwk, kid)
|
||||
|
||||
|
||||
signer_kid = _signer_kid(encoded_jwt)
|
||||
signer_key = _signer_key(signer_kid)
|
||||
|
||||
if signer_key.service != service:
|
||||
abort(403)
|
||||
|
||||
_validate_jwt(encoded_jwt, signer_key.jwk, service)
|
||||
|
||||
metadata = {
|
||||
'ip': request.remote_addr,
|
||||
'signer_jwk': signer_jwk,
|
||||
'created_by': 'Key Rotation',
|
||||
'rotated_by': json.dumps(signer_key),
|
||||
}
|
||||
|
||||
|
||||
try:
|
||||
data.model.service_keys.update_service_key('', kid, metadata, expiration_date)
|
||||
data.model.service_keys.replace_service_key(kid, jwk, metadata, expiration_date)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
data.model.service_keys.create_service_key('', kid, service, jwk, metadata, expiration_date)
|
||||
abort(404)
|
||||
|
||||
|
||||
@key_server.route('/services/<service>/keys/<kid>', methods=['DELETE'])
|
||||
|
@ -115,12 +119,15 @@ def delete_service_key(service, kid):
|
|||
if not encoded_jwt:
|
||||
abort(400)
|
||||
|
||||
signer_jwk = _signer_jwk(encoded_jwt, None, kid)
|
||||
_validate_jwt(encoded_jwt, signer_jwk, service)
|
||||
signer_kid = _signer_kid(encoded_jwt)
|
||||
signer_key = _signer_key(signer_kid)
|
||||
|
||||
try:
|
||||
data.model.service_keys.delete_service_key(service, kid)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
abort(404)
|
||||
if (kid == signer_kid) or (signer_key.approval is not None):
|
||||
_validate_jwt(encoded_jwt, signer_key.jwk, service)
|
||||
try:
|
||||
data.model.service_keys.delete_service_key(service, kid)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
abort(404)
|
||||
return make_response('', 200)
|
||||
|
||||
return make_response('', 200)
|
||||
abort(403)
|
||||
|
|
Reference in a new issue