Do not call chown to config files

This commit fixes a recently discovered issue on Kubernetes #4496
It make necessary to avoid calling `chown` to config files during the
bootstrap of the containers.
This commit is contained in:
Tan Jiang 2018-04-08 23:43:45 +08:00
parent 4da4dd6694
commit 1fc4142e1a
15 changed files with 56 additions and 43 deletions

View File

@ -22,7 +22,7 @@
"realm": "$token_endpoint/service/token", "realm": "$token_endpoint/service/token",
"service": "harbor-notary", "service": "harbor-notary",
"issuer": "harbor-token-issuer", "issuer": "harbor-token-issuer",
"rootcertbundle": "/config/root.crt" "rootcertbundle": "/etc/notary/root.crt"
} }
} }
} }

View File

@ -41,7 +41,7 @@ services:
depends_on: depends_on:
- postgres - postgres
volumes: volumes:
- ./common/config/clair:/config:z - ./common/config/clair/config.yaml:/etc/clair/config.yaml:z
logging: logging:
driver: "syslog" driver: "syslog"
options: options:

View File

@ -15,7 +15,7 @@ services:
- notary-sig - notary-sig
- harbor-notary - harbor-notary
volumes: volumes:
- ./common/config/notary:/config:z - ./common/config/notary:/etc/notary:z
depends_on: depends_on:
- notary-db - notary-db
- notary-signer - notary-signer
@ -34,7 +34,7 @@ services:
aliases: aliases:
- notarysigner - notarysigner
volumes: volumes:
- ./common/config/notary:/config:z - ./common/config/notary:/etc/notary:z
env_file: env_file:
- ./common/config/notary/signer_env - ./common/config/notary/signer_env
depends_on: depends_on:

View File

@ -1,5 +1,4 @@
#!/bin/bash #!/bin/bash
set -e set -e
chown -R 10000:10000 /config sudo -E -H -u \#10000 sh -c "/dumb-init -- /clair2.0.1/clair -config /etc/clair/config.yaml"
sudo -E -H -u \#10000 sh -c "/dumb-init -- /clair2.0.1/clair -config /config/config.yaml"
set +e set +e

View File

@ -1,13 +1,4 @@
#!/bin/sh #!/bin/sh
if [ -d /etc/jobservice/ ]; then
chown -R 10000:10000 /etc/jobservice/
fi
if [ -d /var/log/jobs ]; then
chown -R 10000:10000 /var/log/jobs/
fi
if [ -d /var/log/jobs/scan_job ]; then
chmod +x /var/log/jobs/scan_job
fi
sudo -E -u \#10000 "/harbor/harbor_jobservice" "-c" "/etc/jobservice/config.yml" sudo -E -u \#10000 "/harbor/harbor_jobservice" "-c" "/etc/jobservice/config.yml"

View File

@ -1,3 +1,2 @@
#!/bin/sh #!/bin/sh
chown 10000:10000 -R /config sudo -E -u \#10000 sh -c "/usr/bin/env /migrations/migrate.sh && /bin/notary-server -config=/etc/notary/server-config.json -logf=logfmt"
sudo -E -u \#10000 sh -c "/usr/bin/env /migrations/migrate.sh && /bin/notary-server -config=/config/server-config.json -logf=logfmt"

View File

@ -1,3 +1,2 @@
#!/bin/sh #!/bin/sh
chown 10000:10000 -R /config sudo -E -u \#10000 sh -c "/usr/bin/env && /migrations/migrate.sh && /bin/notary-signer -config=/etc/notary/signer-config.json -logf=logfmt"
sudo -E -u \#10000 sh -c "/usr/bin/env && /migrations/migrate.sh && /bin/notary-signer -config=/config/signer-config.json -logf=logfmt"

View File

@ -2,12 +2,12 @@
set -e set -e
if [ -d /etc/registry ]; then # The directory /var/lib/registry is within the container, and used to store image in CI testing.
chown 10000:10000 -R /etc/registry # So for now we need to chown to it to avoid failure in CI.
fi
if [ -d /var/lib/registry ]; then if [ -d /var/lib/registry ]; then
chown 10000:10000 -R /var/lib/registry chown 10000:10000 -R /var/lib/registry
fi fi
if [ -d /storage ]; then if [ -d /storage ]; then
if ! stat -c '%u:%g' /storage | grep -q '10000:10000' ; then if ! stat -c '%u:%g' /storage | grep -q '10000:10000' ; then
# 10000 is the id of harbor user/group. # 10000 is the id of harbor user/group.

View File

@ -1,6 +1,3 @@
#!/bin/sh #!/bin/sh
if [ -d /etc/ui/ ]; then
chown -R 10000:10000 /etc/ui/
fi
sudo -E -u \#10000 "/harbor/harbor_ui" sudo -E -u \#10000 "/harbor/harbor_ui"

View File

@ -19,6 +19,9 @@ if sys.version_info[:3][0] == 3:
import configparser as ConfigParser import configparser as ConfigParser
import io as StringIO import io as StringIO
DATA_VOL = "/data"
JOB_LOG_DIR = os.path.join(DATA_VOL, "job_logs")
def validate(conf, args): def validate(conf, args):
if args.ha_mode: if args.ha_mode:
db_host = rcp.get("configuration", "db_host") db_host = rcp.get("configuration", "db_host")
@ -68,6 +71,12 @@ def validate(conf, args):
if project_creation != "everyone" and project_creation != "adminonly": if project_creation != "everyone" and project_creation != "adminonly":
raise Exception("Error invalid value for project_creation_restriction: %s" % project_creation) raise Exception("Error invalid value for project_creation_restriction: %s" % project_creation)
#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=10000, gid=10000):
os.chmod(path, mode)
os.chown(path, uid, gid)
def prepare_ha(conf, args): def prepare_ha(conf, args):
#files under ha folder will have high prority #files under ha folder will have high prority
protocol = rcp.get("configuration", "ui_url_protocol") protocol = rcp.get("configuration", "ui_url_protocol")
@ -88,7 +97,7 @@ def prepare_ha(conf, args):
if os.path.isfile(cert_path): if os.path.isfile(cert_path):
shutil.copy2(cert_path, shared_cert_path) shutil.copy2(cert_path, shared_cert_path)
#check if ca exsit #check if ca exsit
cert_ca_path = "/data/ca_download/ca.crt" cert_ca_path = os.path.join(DATA_VOL, 'ca_download', 'ca.crt')
shared_ca_path = os.path.join(base_dir, "ha", os.path.basename(cert_ca_path)) shared_ca_path = os.path.join(base_dir, "ha", os.path.basename(cert_ca_path))
if os.path.isfile(shared_ca_path): if os.path.isfile(shared_ca_path):
shutil.copy2(shared_ca_path, cert_ca_path) shutil.copy2(shared_ca_path, cert_ca_path)
@ -138,16 +147,16 @@ def _get_secret(folder, filename, length=16):
print("loaded secret from file: %s" % key_file) print("loaded secret from file: %s" % key_file)
return key return key
if not os.path.isdir(folder): if not os.path.isdir(folder):
os.makedirs(folder, mode=0o600) os.makedirs(folder)
key = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(length)) key = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(length))
with open(key_file, 'w') as f: with open(key_file, 'w') as f:
f.write(key) f.write(key)
print("Generated and saved secret to file: %s" % key_file) print("Generated and saved secret to file: %s" % key_file)
os.chmod(key_file, 0o600) mark_file(key_file)
return key return key
def prep_conf_dir(root, name): def prep_conf_dir(root, *name):
absolute_path = os.path.join(root, name) absolute_path = os.path.join(root, *name)
if not os.path.exists(absolute_path): if not os.path.exists(absolute_path):
os.makedirs(absolute_path) os.makedirs(absolute_path)
return absolute_path return absolute_path
@ -173,6 +182,10 @@ def delfile(src):
itemsrc=os.path.join(src,item) itemsrc=os.path.join(src,item)
delfile(itemsrc) delfile(itemsrc)
if not os.path.exists(JOB_LOG_DIR):
os.makedirs(JOB_LOG_DIR)
mark_file(JOB_LOG_DIR, mode=0o755)
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--conf', dest='cfgfile', default=base_dir+'/harbor.cfg',type=str,help="the path of Harbor configuration file") parser.add_argument('--conf', dest='cfgfile', default=base_dir+'/harbor.cfg',type=str,help="the path of Harbor configuration file")
parser.add_argument('--with-notary', dest='notary_mode', default=False, action='store_true', help="the Harbor instance is to be deployed with notary") parser.add_argument('--with-notary', dest='notary_mode', default=False, action='store_true', help="the Harbor instance is to be deployed with notary")
@ -431,7 +444,7 @@ shutil.copyfile(os.path.join(templates_dir, "ui", "app.conf"), ui_conf)
if auth_mode == "uaa_auth": if auth_mode == "uaa_auth":
if os.path.isfile(uaa_ca_cert): if os.path.isfile(uaa_ca_cert):
if not os.path.isdir(ui_cert_dir): if not os.path.isdir(ui_cert_dir):
os.makedirs(ui_cert_dir, mode=0o600) os.makedirs(ui_cert_dir)
ui_uaa_ca = os.path.join(ui_cert_dir, "uaa_ca.pem") ui_uaa_ca = os.path.join(ui_cert_dir, "uaa_ca.pem")
print("Copying UAA CA cert to %s" % ui_uaa_ca) print("Copying UAA CA cert to %s" % ui_uaa_ca)
shutil.copyfile(uaa_ca_cert, ui_uaa_ca) shutil.copyfile(uaa_ca_cert, ui_uaa_ca)
@ -491,8 +504,8 @@ if customize_crt == 'on' and openssl_installed():
private_key_pem = os.path.join(config_dir, "ui", "private_key.pem") private_key_pem = os.path.join(config_dir, "ui", "private_key.pem")
root_crt = os.path.join(config_dir, "registry", "root.crt") root_crt = os.path.join(config_dir, "registry", "root.crt")
create_root_cert(empty_subj, key_path=private_key_pem, cert_path=root_crt) create_root_cert(empty_subj, key_path=private_key_pem, cert_path=root_crt)
os.chmod(private_key_pem, 0o600) mark_file(private_key_pem)
os.chmod(root_crt, 0o600) mark_file(root_crt)
else: else:
print("Copied configuration file: %s" % ui_config_dir + "private_key.pem") print("Copied configuration file: %s" % ui_config_dir + "private_key.pem")
shutil.copyfile(os.path.join(templates_dir, "ui", "private_key.pem"), os.path.join(ui_config_dir, "private_key.pem")) shutil.copyfile(os.path.join(templates_dir, "ui", "private_key.pem"), os.path.join(ui_config_dir, "private_key.pem"))
@ -520,9 +533,6 @@ if args.notary_mode:
create_root_cert(ca_subj, key_path=signer_ca_key, cert_path=signer_ca_cert) create_root_cert(ca_subj, key_path=signer_ca_key, cert_path=signer_ca_cert)
create_cert(cert_subj, signer_ca_key, signer_ca_cert, key_path=signer_key_path, cert_path=signer_cert_path) create_cert(cert_subj, signer_ca_key, signer_ca_cert, key_path=signer_key_path, cert_path=signer_cert_path)
print("Copying certs for notary signer") print("Copying certs for notary signer")
os.chmod(signer_cert_path, 0o600)
os.chmod(signer_key_path, 0o600)
os.chmod(signer_ca_cert, 0o600)
shutil.copy2(signer_cert_path, notary_config_dir) shutil.copy2(signer_cert_path, notary_config_dir)
shutil.copy2(signer_key_path, notary_config_dir) shutil.copy2(signer_key_path, notary_config_dir)
shutil.copy2(signer_ca_cert, notary_config_dir) shutil.copy2(signer_ca_cert, notary_config_dir)
@ -538,6 +548,10 @@ if args.notary_mode:
shutil.copy2(os.path.join(notary_temp_dir, "notary-signer.key"), notary_config_dir) shutil.copy2(os.path.join(notary_temp_dir, "notary-signer.key"), notary_config_dir)
shutil.copy2(os.path.join(notary_temp_dir, "notary-signer-ca.crt"), notary_config_dir) shutil.copy2(os.path.join(notary_temp_dir, "notary-signer-ca.crt"), notary_config_dir)
shutil.copy2(os.path.join(registry_config_dir, "root.crt"), notary_config_dir) shutil.copy2(os.path.join(registry_config_dir, "root.crt"), notary_config_dir)
mark_file(os.path.join(notary_config_dir, "notary-signer.crt"))
mark_file(os.path.join(notary_config_dir, "notary-signer.key"))
mark_file(os.path.join(notary_config_dir, "notary-signer-ca.crt"))
mark_file(os.path.join(notary_config_dir, "root.crt"))
print("Copying notary signer configuration file") print("Copying notary signer configuration file")
shutil.copy2(os.path.join(notary_temp_dir, "signer-config.json"), notary_config_dir) shutil.copy2(os.path.join(notary_temp_dir, "signer-config.json"), notary_config_dir)
render(os.path.join(notary_temp_dir, "server-config.json"), render(os.path.join(notary_temp_dir, "server-config.json"),

View File

@ -36,7 +36,7 @@ import (
) )
var ( var (
notaryCachePath = "/etc/ui/notary-cache" notaryCachePath = "/tmp/notary-cache"
trustPin trustpinning.TrustPinConfig trustPin trustpinning.TrustPinConfig
mockRetriever notary.PassRetriever mockRetriever notary.PassRetriever
) )

View File

@ -38,8 +38,9 @@ import (
) )
const ( const (
defaultKeyPath string = "/etc/ui/key" defaultKeyPath = "/etc/ui/key"
defaultTokenFilePath string = "/etc/ui/token/tokens.properties" defaultTokenFilePath = "/etc/ui/token/tokens.properties"
defaultRegistryTokenPrivateKeyPath = "/etc/ui/private_key.pem"
) )
var ( var (
@ -56,7 +57,7 @@ var (
AdmiralClient *http.Client AdmiralClient *http.Client
// TokenReader is used in integration mode to read token // TokenReader is used in integration mode to read token
TokenReader admiral.TokenReader TokenReader admiral.TokenReader
// defined as a var for testing.
defaultCACertPath = "/etc/ui/ca/ca.crt" defaultCACertPath = "/etc/ui/ca/ca.crt"
) )
@ -189,6 +190,15 @@ func AuthMode() (string, error) {
return cfg[common.AUTHMode].(string), nil return cfg[common.AUTHMode].(string), nil
} }
// TokenPrivateKeyPath returns the path to the key for signing token for registry
func TokenPrivateKeyPath() string {
path := os.Getenv("TOKEN_PRIVATE_KEY_PATH")
if len(path) == 0 {
path = defaultRegistryTokenPrivateKeyPath
}
return path
}
// LDAPConf returns the setting of ldap server // LDAPConf returns the setting of ldap server
func LDAPConf() (*models.LdapConf, error) { func LDAPConf() (*models.LdapConf, error) {
cfg, err := mg.Get() cfg, err := mg.Get()

View File

@ -185,6 +185,10 @@ func TestConfig(t *testing.T) {
t.Errorf("unexpected scan all policy %v", s) t.Errorf("unexpected scan all policy %v", s)
} }
if tokenKeyPath := TokenPrivateKeyPath(); tokenKeyPath != "/etc/ui/private_key.pem" {
t.Errorf("Unexpected token private key path: %s, expected: %s", tokenKeyPath, "/etc/ui/private_key.pem")
}
us, err := UAASettings() us, err := UAASettings()
if err != nil { if err != nil {
t.Fatalf("failed to get UAA setting, error: %v", err) t.Fatalf("failed to get UAA setting, error: %v", err)

View File

@ -39,7 +39,7 @@ const (
var privateKey string var privateKey string
func init() { func init() {
privateKey = "/etc/ui/private_key.pem" privateKey = config.TokenPrivateKeyPath()
} }
// GetResourceActions ... // GetResourceActions ...

View File

@ -3,10 +3,10 @@ set -e
cp tests/docker-compose.test.yml make/. cp tests/docker-compose.test.yml make/.
mkdir -p /etc/ui mkdir -p /etc/ui
cp make/common/config/ui/private_key.pem /etc/ui/. cp make/common/config/ui/private_key.pem /etc/ui/
mkdir src/ui/conf mkdir src/ui/conf
cp make/common/config/ui/app.conf src/ui/conf/. cp make/common/config/ui/app.conf src/ui/conf/
IP=`ip addr s eth0 |grep "inet "|awk '{print $2}' |awk -F "/" '{print $1}'` IP=`ip addr s eth0 |grep "inet "|awk '{print $2}' |awk -F "/" '{print $1}'`
echo "server ip is "$IP echo "server ip is "$IP
sed -i -r "s/MYSQL_HOST=mysql/MYSQL_HOST=$IP/" make/common/config/adminserver/env sed -i -r "s/MYSQL_HOST=mysql/MYSQL_HOST=$IP/" make/common/config/adminserver/env