Skip to content

Commit

Permalink
fix: set username and password on proxy properly
Browse files Browse the repository at this point in the history
Add environment variables to container to configure proxy rather than
encode credentials in proxy URL

fixes #24
  • Loading branch information
stuart-warren committed Aug 23, 2018
1 parent 914c166 commit b62d43f
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 334 deletions.
145 changes: 53 additions & 92 deletions mirroroperator/registrymirror.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,106 +253,47 @@ def generate_headless_service(self, service_headless):
service_headless.spec.type = "ClusterIP"
return service_headless

def generate_new_auth_url(self, credentials_secret):
"""
Method which, given a credentials secret (secret named <self.credentials_secret_name>):
- decodes the username/password
- if they are valid, create a new authed upstream url
Args:
credentials_secret: V1Secret
Returns: base64-encoded str or None if the url was not valid
def handle_proxy_credentials(self, env):
credentials_secret = None
if self.credentials_secret_name:
credentials_secret = self.run_action_and_parse_error(self.core_api.read_namespaced_secret,
self.credentials_secret_name,
self.namespace)
if not credentials_secret:
LOGGER.error("No secret named %s was found in the %s namespace, will use unauth access",
self.credentials_secret_name, self.namespace)
return env

"""
encoded_user = credentials_secret.data.get("username")
encoded_pass = credentials_secret.data.get("password")
url = None
if not (encoded_pass and encoded_user):
# log an error, keep the url at none
LOGGER.error("Secret %s does not contain username/password, defaulting to %s",
self.credentials_secret_name, self.upstreamUrl)
else:
# decode the username, update the url
username = base64.b64decode(encoded_user).decode('utf-8')
password = base64.b64decode(encoded_pass).decode('utf-8')
decoded_url = "https://{}:{}@{}".format(username, password, self.upstreamUrl)
url = base64.b64encode(decoded_url.encode('utf-8')).decode('utf-8')

return url

def handle_secrets(self, keypair):
credentials_secret = self.run_action_and_parse_error(self.core_api.read_namespaced_secret,
self.credentials_secret_name,
self.namespace)
reg_secret = self.run_action_and_parse_error(self.core_api.read_namespaced_secret,
self.full_name, self.namespace)
valid_secret = None
url = None
if credentials_secret:
# create a new url
url = self.generate_new_auth_url(credentials_secret)

else:
LOGGER.error("No secret named %s was found, will use unauth access",
if not (encoded_user and encoded_pass):
LOGGER.error("Secret %s does not contain username/password",
self.credentials_secret_name)
return env
env.append(client.V1EnvVar(name="REGISTRY_PROXY_USERNAME",
value=None,
value_from=client.V1EnvVarSource(
secret_key_ref=client.V1SecretKeySelector(
key="username",
name=self.credentials_secret_name
)
))
)
env.append(client.V1EnvVar(name="REGISTRY_PROXY_PASSWORD",
value=None,
value_from=client.V1EnvVarSource(
secret_key_ref=client.V1SecretKeySelector(
key="password",
name=self.credentials_secret_name
)
))
)
LOGGER.info("Secret selected + env vars set successfully")
return env

if url:
if reg_secret:
reg_secret.metadata = self.metadata
reg_secret.data = {"url": url}
LOGGER.info("Updating the secret %s", self.full_name)
valid_secret = self.run_action_and_parse_error(
self.core_api.replace_namespaced_secret,
self.full_name, self.namespace, reg_secret
)
else:
# create a new one
reg_secret = client.V1Secret(
metadata=self.metadata,
data={"url": url}
)
LOGGER.info("Creating new secret %s", self.full_name)
valid_secret = self.run_action_and_parse_error(self.core_api.create_namespaced_secret,
self.namespace, reg_secret)

if valid_secret:
keypair.value = None
keypair.value_from = client.V1EnvVarSource(
secret_key_ref=client.V1SecretKeySelector(
key="url",
name=valid_secret.metadata.name
)
)
LOGGER.info("Secret selected + env var set successfully")
else:
LOGGER.error("Valid authenticated url secret could not be created or found, value will default to upstream url %s",
self.upstreamUrl)

return keypair

def generate_stateful_set(self, stateful_set):
keypair = client.V1EnvVar(
name="REGISTRY_PROXY_REMOTEURL",
value="https://" + self.upstreamUrl)
if self.credentials_secret_name:
keypair = self.handle_secrets(keypair)

env = [client.V1EnvVar(name="REGISTRY_HTTP_ADDR",
value=":5000"),
client.V1EnvVar(name="REGISTRY_HTTP_DEBUG_ADDR",
value="localhost:6000"),
client.V1EnvVar(name="REGISTRY_HTTP_TLS_CERTIFICATE",
value="/etc/registry-certs/tls.crt"),
client.V1EnvVar(name="REGISTRY_HTTP_TLS_KEY",
value="/etc/registry-certs/tls.key"),
keypair,
client.V1EnvVar(name="REGISTRY_LOG_FORMATTER",
value="logstash"),
client.V1EnvVar(name="REGISTRY_STORAGE_DELETE_ENABLED",
value="true"),
client.V1EnvVar(name="REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY",
value="/var/lib/registry")
]
stateful_set.metadata = self.metadata
stateful_set.spec.replicas = 2
pod_labels = {'component': 'registry'}
Expand Down Expand Up @@ -395,6 +336,26 @@ def generate_stateful_set(self, stateful_set):
read_only=True
)
)

env = [client.V1EnvVar(name="REGISTRY_PROXY_REMOTEURL",
value="https://" + self.upstreamUrl),
client.V1EnvVar(name="REGISTRY_HTTP_ADDR",
value=":5000"),
client.V1EnvVar(name="REGISTRY_HTTP_DEBUG_ADDR",
value="localhost:6000"),
client.V1EnvVar(name="REGISTRY_HTTP_TLS_CERTIFICATE",
value="/etc/registry-certs/tls.crt"),
client.V1EnvVar(name="REGISTRY_HTTP_TLS_KEY",
value="/etc/registry-certs/tls.key"),
client.V1EnvVar(name="REGISTRY_LOG_FORMATTER",
value="logstash"),
client.V1EnvVar(name="REGISTRY_STORAGE_DELETE_ENABLED",
value="true"),
client.V1EnvVar(name="REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY",
value="/var/lib/registry")
]
env = self.handle_proxy_credentials(env)

stateful_set.spec.template = client.V1PodTemplateSpec(
metadata=client.V1ObjectMeta(
labels=pod_labels
Expand Down
20 changes: 1 addition & 19 deletions tests/kubernetes_mock_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,25 +202,7 @@
},
"type": "Opaque"
}
url = "https://{}:{}@{}".format(username, password, "hubtest")
url = base64.b64encode(url.encode('utf-8')).decode('utf-8')
valid_reg_secret = {
"apiVersion": "v1",
"data": {
"url": url
},
"kind": "Secret",
"metadata": {
"creationTimestamp": "2017-09-13T10:20:26Z",
"name": "registry-mirror-hub",
"namespace": "default",
"resourceVersion": "7889",
"selfLink": "/api/v1/namespaces/default/secrets/internal-mirror",
"uid": "294e16e7-986d-11e7-9c1f-0800275e72fe"
},
"type": "Opaque"
}
VALID_REG_SECRET = json.dumps(valid_reg_secret)

VALID_SECRET = json.dumps(valid_secret)

INVALID_SECRET = """
Expand Down
2 changes: 1 addition & 1 deletion tests/test_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def test_will_read_crds_blanks_already_exist(self):

@responses.activate
def test_will_read_crds_blanks_dont_exist(self):
'''Should listen to CRDs being streamed + call apis appropriately. In this case the objects don't alreadu exist'''
'''Should listen to CRDs being streamed + call apis appropriately. In this case the objects don't already exist'''
stream_generator = stream_mock()
responses.add('GET', '/api/v1/namespaces/default/services/registry-mirror-hub', status=404, body='{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"services \\"registry-mirror-internal\\" not found","reason":"NotFound","details":{"name":"registry-mirror-internal","kind":"services"},"code":404}')
responses.add('GET', '/api/v1/namespaces/default/services/registry-mirror-hub-headless', status=404)
Expand Down
Loading

0 comments on commit b62d43f

Please sign in to comment.