IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    搭建可认证的docker registry

    istrone发表于 2016-09-13 02:55:20
    love 0

    1. 生成rsa 配对的公钥私钥

    openssl genrsa -out ./private_key.pem 4096
    openssl req -new -x509 -key ./private_key.pem -out ./root.crt -days 3650 -subj /C=CN/ST=state/L=CN/O=cloverstd/OU=cloverstd\ unit/CN=hui.lu/emailAddress=xingyue@staff.sina.com.cn
    

    2. pull registry v2

    docker pull registry:2.1.1
    

    3. 修改配置文件config.yml

    version: 0.1
    log:
      level: debug
      fields:
        service: registry
        environment: development
    storage:
        cache:
            layerinfo: inmemory
        filesystem:
            rootdirectory: /tmp/registry-dev
        maintenance:
            uploadpurging:
                enabled: false
    http:
        addr: :5000
        secret: asecretforlocaldevelopment
        debug:
            addr: localhost:5001
    
    auth:  
        token: 
            issuer: registry-token-issuer
            realm: http://192.168.122.186:8080/service/token
            rootcertbundle: /etc/registry/root.crt
            service: token-service
    
    redis:
      addr: localhost:6379
      pool:
        maxidle: 16
        maxactive: 64
        idletimeout: 300s
      dialtimeout: 10ms
      readtimeout: 10ms
      writetimeout: 10ms
    notifications:
        endpoints:
            - name: local-8082
              url: http://localhost:5003/callback
              headers:
                 Authorization: [Bearer <an example token>]
              timeout: 1s
              threshold: 10
              backoff: 1s
              disabled: true
            - name: local-8083
              url: http://localhost:8083/callback
              timeout: 1s
              threshold: 10
              backoff: 1s
              disabled: true
       
    

    4. 重新编译生成新的auth_registy:

    FROM docker.io/registry:2.0
    COPY config.yml /go/src/github.com/docker/distribution/cmd/registry/config.yml
    

    5. 启动docker registry
    [/shell]
    docker run -d -p 5000:5000 -v /opt/registry:/var/lib/registry -v `pwd`/root.crt:/etc/registry/root.crt:ro auth_registry
    [/shell]
    6.添加认证的python脚本:

    from flask import Flask, request, jsonify, make_response, json  
    import base64  
    import jwt  
    from cryptography.hazmat.backends import default_backend  
    from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat, load_pem_private_key  
    import time  
    import os  
    import hashlib
    
    app = Flask(__name__)
    
    SERVICE = 'token-service'  
    ISSUER = 'registry-token-issuer'
    
    
    class DockerRegistryAuth(object):
    
        def __init__(self, account, scopes, service, issuer, private_key_path, token_expires=300):
            self.account = account
            self.issuer = issuer
            self.scopes = scopes
            self.access = self.get_access_by_scopes(scopes)
            self.service = service
            self.private_key_path = private_key_path
            self.token_expires = token_expires
    
        @property
        def private_key(self):
            if getattr(self, '_private_key_content', None):
                return self._private_key_content
    
            with open(self.private_key_path, 'r') as fp:
                setattr(self, '_private_key_content', fp.read())
                return self._private_key_content
    
        @property
        def public_key(self):
            private_key = load_pem_private_key(
                    self.private_key,
                    password=None,
                    backend=default_backend()
            )
            _public_key = private_key.public_key()
            return _public_key
    
        def check_service(self, service):
            return self.service == service
    
        def get_token(self):
            now = int(time.time())
    
            claim = {
                'iss': self.issuer,
                'sub': self.account,
                'aud': self.service,
                'exp': now + self.token_expires,
                'nbf': now,
                'iat': now,
                'jti': base64.b64encode(os.urandom(1024)),
                'access': self.access
            }
    
            headers = {
                'kid': self.get_kid()
            }
            token = jwt.encode(claim, self.private_key, algorithm='RS256', headers=headers)
            return {
                'token': token,
                'issued_at': now,
                'expires_in': now + self.token_expires
            }
    
        def get_kid(self):
            der_public_key = self.public_key.public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
    
            sha256 = hashlib.sha256(der_public_key)
            base32_payload = base64.b32encode(sha256.digest()[:30]) # 240bits / 8
            return ":".join(
                [base32_payload[i:i+4] for i in xrange(0, 48, 4)]
            )
    
    
        def get_login_info(self, authorization):
            if not authorization:
                return None
            auth_info = authorization
            if authorization.startswith('Basic'):
                auth_info = authorization[5:]
    
            user_info = base64.b64decode(auth_info)
            self.username, self.password = user_info.split(':')
            return {
                'username': self.username,
                'password': self.password,
            }
    
        def get_access_by_scopes(self, scopes):
            access = list()
            if not scopes:
                return access
            for scope in scopes:
                type_, name, actions = scope.split(':')
                access.append({
                    'type': type_,
                    'name': name,
                    'actions': actions.split(',')
                })
    
            return access
    
    def unauthorized401(access, message=None, code=None):  
        detail = list()
        for scope in access:
            for action in scope['actions']:
                detail.append({
                    "Action": action,
                    "Name": scope['name'],
                    "Type": scope['type']
                })
        data = {
            "errors": [
                {
                    "code": code or "UNAUTHORIZED",
                    "detail": detail,
                    "message": message or "access to the requested resource is not authorized"
                }
            ]
        }
        resp = make_response(json.dumps(data), 401)
        resp.headers['Content-Type'] = 'application/json; charset=utf-8'
        resp.headers['Docker-Distribution-Api-Version'] = 'registry/2.0'
        resp.headers['Www-Authenticate'] = 'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push"'
        return resp
    
    
    @app.route('/service/token')
    def service_token():  
        print request.headers
        scopes = request.args.getlist('scope')
        account = request.args.get('account')
        client_id = request.args.get('client_id')
        service = request.args.get('service')
        http_base_auth = request.headers.get('Authorization')
    
        registry_auth = DockerRegistryAuth(account, scopes, SERVICE, ISSUER, './private_key.pem')
        if not registry_auth.check_service(service):
            return unauthorized401(registry_auth.access, 'service not be allowed.')
        user = registry_auth.get_login_info(http_base_auth)
    
        if user:
            if not (user['username'] == 'test' and user['password'] == 'test'):
                return unauthorized401(registry_auth.access, 'incorrect username or password')
            res = registry_auth.get_token()
            return jsonify(
                token=res['token'],
            )
    
        return unauthorized401(registry_auth.access)
    
    if __name__ == '__main__':  
        app.run(host='0.0.0.0', port=8080, debug=True)
    

    7.安装需要的包:
    pip install PyJWT

    8. 启动认证脚本:
    python auth.py

    9. 测试登录:
    docker login localhost:5000
    test:test:x@s.com

    然后成功获得token 则登录成功.

    Maybe you like these:
    用jquery实现下拉列表的联动
    大海,誓言
    再见青春
    哪一站【突然感觉,现在的心情跟现在好像呢】
    如果可以,请在42.195公里之后等我
    无觅


沪ICP备19023445号-2号
友情链接