Populate basic auth information for registry

This commit updates `prepare` and templates to populate the credential
for registry for basic authentication.

A temporary flag `registry_use_basic_auth` was added to avoid breakage.
It MUST be removed before the release.

Signed-off-by: Daniel Jiang <jiangd@vmware.com>
This commit is contained in:
Daniel Jiang 2019-12-25 14:59:47 +08:00
parent 79f93af471
commit a087ba02e3
10 changed files with 61 additions and 24 deletions

View File

@ -26,6 +26,9 @@ https:
# Remember Change the admin password from UI after launching Harbor.
harbor_admin_password: Harbor12345
#TODO: remove this temporary flag before ships v1.11/v2, this should always be true
registry_use_basic_auth: false
# Harbor DB configuration
database:
# The password for the root user of Harbor DB. Change this before any production use.

View File

@ -1,5 +1,6 @@
FROM photon:2.0
RUN tdnf install -y python3 \
&& tdnf install -y python3-pip
RUN pip3 install pipenv==2018.11.26
RUN tdnf install -y python3 python3-pip httpd
RUN pip3 install pipenv==2018.11.26

View File

@ -35,7 +35,7 @@ def main(conf, with_notary, with_clair, with_chartmuseum):
try:
validate(config_dict, notary_mode=with_notary)
except Exception as e:
logging.info('Error happend in config validation...')
logging.info('Error happened in config validation...')
logging.error(e)
sys.exit(-1)

View File

@ -44,6 +44,8 @@ RELOAD_KEY={{reload_key}}
CHART_REPOSITORY_URL={{chart_repository_url}}
REGISTRY_CONTROLLER_URL={{registry_controller_url}}
WITH_CHARTMUSEUM={{with_chartmuseum}}
REGISTRY_CREDENTIAL_USERNAME={{registry_username}}
REGISTRY_CREDENTIAL_PASSWORD={{registry_password}}
HTTP_PROXY={{core_http_proxy}}
HTTPS_PROXY={{core_https_proxy}}

View File

@ -26,11 +26,17 @@ http:
debug:
addr: localhost:5001
auth:
{% if registry_use_basic_auth %}
htpasswd:
realm: harbor-registry-basic-realm
path: /etc/registry/passwd
{% else %}
token:
issuer: harbor-token-issuer
realm: {{public_url}}/service/token
rootcertbundle: /etc/registry/root.crt
service: harbor-registry
{% endif %}
validation:
disabled: true
notifications:

View File

@ -1,14 +1,14 @@
# Get or generate private key
import os, sys, subprocess, shutil
import os, subprocess, shutil
from pathlib import Path
from subprocess import DEVNULL
from functools import wraps
from g import DEFAULT_GID, DEFAULT_UID
from .misc import (
mark_file,
generate_random_string,
check_permission)
check_permission,
stat_decorator)
SSL_CERT_PATH = os.path.join("/etc/cert", "server.crt")
SSL_CERT_KEY_PATH = os.path.join("/etc/cert", "server.key")
@ -44,19 +44,6 @@ def get_alias(path):
alias = _get_secret(path, "defaultalias", length=8)
return alias
## decorator actions
def stat_decorator(func):
@wraps(func)
def check_wrapper(*args, **kw):
stat = func(*args, **kw)
if stat == 0:
print("Generated certificate, key file: {key_path}, cert file: {cert_path}".format(**kw))
else:
print("Fail to generate key file: {key_path}, cert file: {cert_path}".format(**kw))
sys.exit(1)
return check_wrapper
@stat_decorator
def create_root_cert(subj, key_path="./k.key", cert_path="./cert.crt"):
rc = subprocess.call(["/usr/bin/openssl", "genrsa", "-out", key_path, "4096"], stdout=DEVNULL, stderr=subprocess.STDOUT)

View File

@ -9,6 +9,8 @@ default_db_max_open_conns = 0 # NOTE: https://golang.org/pkg/database/sql/#DB.S
default_https_cert_path = '/your/certificate/path'
default_https_key_path = '/your/certificate/path'
REGISTRY_USER_NAME = 'harbor_registry_user'
def validate(conf: dict, **kwargs):
# hostname validate
@ -83,6 +85,7 @@ def validate(conf: dict, **kwargs):
# TODO:
# If user enable trust cert dir, need check if the files in this dir is readable.
def parse_versions():
if not versions_file_path.is_file():
return {}
@ -90,6 +93,7 @@ def parse_versions():
versions = yaml.load(f)
return versions
def parse_yaml_config(config_file_path, with_notary, with_clair, with_chartmuseum):
'''
:param configs: config_parser object
@ -321,6 +325,12 @@ def parse_yaml_config(config_file_path, with_notary, with_clair, with_chartmuseu
# UAA configs
config_dict['uaa'] = configs.get('uaa') or {}
config_dict['registry_username'] = REGISTRY_USER_NAME
config_dict['registry_password'] = generate_random_string(32)
# TODO: remove the flag before release
config_dict['registry_use_basic_auth'] = configs['registry_use_basic_auth']
return config_dict

View File

@ -1,11 +1,10 @@
import os
import string
import os, string, sys
import secrets
from pathlib import Path
from functools import wraps
from g import DEFAULT_UID, DEFAULT_GID
# To meet security requirement
# By default it will change file mode to 0600, and make the owner of the file to 10000:10000
def mark_file(path, mode=0o600, uid=DEFAULT_UID, gid=DEFAULT_GID):
@ -154,3 +153,18 @@ def other_can_read(st_mode: int) -> bool:
Check if other user have the read permission of this st_mode
"""
return True if st_mode & 0o004 else False
# decorator actions
def stat_decorator(func):
@wraps(func)
def check_wrapper(*args, **kw):
stat = func(*args, **kw)
if stat == 0:
print("Successfully called func: %s" % func.__name__)
else:
print("Failed to call func: %s" % func.__name__)
sys.exit(1)
return check_wrapper

View File

@ -1,4 +1,4 @@
import os, copy
import os, copy, subprocess
from g import config_dir, templates_dir, DEFAULT_GID, DEFAULT_UID, data_dir
from utils.misc import prepare_dir
@ -8,6 +8,7 @@ from utils.jinja import render_jinja
registry_config_dir = os.path.join(config_dir, "registry")
registry_config_template_path = os.path.join(templates_dir, "registry", "config.yml.jinja")
registry_conf = os.path.join(config_dir, "registry", "config.yml")
registry_passwd_path = os.path.join(config_dir, "registry", "passwd")
registry_data_dir = os.path.join(data_dir, 'registry')
levels_map = {
@ -18,10 +19,13 @@ levels_map = {
'fatal': 'fatal'
}
def prepare_registry(config_dict):
prepare_dir(registry_data_dir, uid=DEFAULT_UID, gid=DEFAULT_GID)
prepare_dir(registry_config_dir)
if config_dict['registry_use_basic_auth']:
gen_passwd_file(config_dict)
storage_provider_info = get_storage_provider_info(
config_dict['storage_provider_name'],
config_dict['storage_provider_config'])
@ -55,3 +59,8 @@ def get_storage_provider_info(provider_name, provider_config):
storage_provider_conf_list.append('{}: {}'.format(config[0], value))
storage_provider_info = ('\n' + ' ' * 4).join(storage_provider_conf_list)
return storage_provider_info
def gen_passwd_file(config_dict):
return subprocess.call(["/usr/bin/htpasswd", "-bcB", registry_passwd_path, config_dict['registry_username'],
config_dict['registry_password']], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)

View File

@ -299,6 +299,11 @@ func CoreSecret() string {
return os.Getenv("CORE_SECRET")
}
// RegistryCredential returns the username and password the core uses to access registry
func RegistryCredential() (string, string) {
return os.Getenv("REGISTRY_CREDENTIAL_USERNAME"), os.Getenv("REGISTRY_CREDENTIAL_PASSWORD")
}
// JobserviceSecret returns a secret to mark Jobservice when communicate with
// other component
// TODO replace it with method of SecretStore