Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ spec:
secret:
secretName: {{ include "eric-oss-hello-world-python-app.clientSecret" . | quote }}
defaultMode: 420
- name: app-sef-certs
secret:
secretName: {{ index .Values "appSefSecretName" | quote }}
defaultMode: 420
- name: platform-sef-cacerts
secret:
secretName: {{ index .Values "platformCaCertSecretName" | quote }}
defaultMode: 420
containers:
- name: eric-oss-hello-world-python-app
image: {{ template "eric-oss-hello-world-python-app.imagePath" (dict "imageId" "eric-oss-hello-world-python-app" "values" .Values "files" .Files) }}
Expand Down Expand Up @@ -96,6 +104,12 @@ spec:
- name: client-creds
mountPath: {{ index .Values "clientCredsMountPath" | default .Values.instantiationDefaults.clientCredsMountPath | quote }}
readOnly: true
- name: app-sef-certs
mountPath: {{ index .Values "appSefCredsMountPath" | default .Values.instantiationDefaults.appSefCredsMountPath | quote }}
readOnly: true
- name: platform-sef-cacerts
mountPath: {{ index .Values "platformSefCaCertMountPath" | default .Values.instantiationDefaults.platformSefCaCertMountPath | quote }}
readOnly: true
env:
- name: IAM_CLIENT_ID
value: {{ index .Values "clientId" | quote }}
Expand All @@ -109,12 +123,22 @@ spec:
value: {{ index .Values "platformCaCertMountPath" | default .Values.instantiationDefaults.platformCaCertMountPath | quote }}
- name: CA_CERT_FILE_NAME
value: {{ index .Values "platformCaCertFileName" | quote }}
- name: CA_SEF_CERT_FILE_PATH
value: {{ index .Values "platformSefCaCertMountPath" | default .Values.instantiationDefaults.platformSefCaCertMountPath | quote }}
- name: CA_SEF_CERT_FILE_NAME
value: {{ index .Values "platformSefCaCertFileName" | quote }}
- name: APP_KEY
value: {{ index .Values "appKeyFileName" | quote }}
- name: APP_CERT
value: {{ index .Values "appCertFileName" | quote }}
- name: APP_CERT_FILE_PATH
value: {{ index .Values "appCertMountPath" | default .Values.instantiationDefaults.appCertMountPath | quote }}
- name: APP_SEF_KEY
value: {{ index .Values "appSefKeyFileName" | quote }}
- name: APP_SEF_CERT
value: {{ index .Values "appSefCertFileName" | quote }}
- name: APP_SEF_CERT_FILE_PATH
value: {{ index .Values "appSefCertMountPath" | default .Values.instantiationDefaults.appSefCertMountPath | quote }}
- name: CLIENT_CREDS_FILE_PATH
value: {{ index .Values "clientCredsMountPath" | default .Values.instantiationDefaults.clientCredsMountPath | quote }}
- name: CLIENT_ID_FILE_NAME
Expand Down
6 changes: 4 additions & 2 deletions charts/eric-oss-hello-world-python-app/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ global:
timezone: UTC
registry:
url: armdocker.rnd.ericsson.se
imagePullPolicy: IfNotPresent
imagePullPolicy: Always
pullSecret:
internalIPFamily:

imageCredentials:
repoPath:
pullPolicy: IfNotPresent
pullPolicy: Always
registry:
url:
pullSecret:
Expand Down Expand Up @@ -127,6 +127,8 @@ instantiationDefaults:
platformCaCertMountPath: "/etc/tls-ca/platform/"
appCertMountPath: "/etc/tls/log/"
clientCredsMountPath: "/etc/client-creds/"
platformSefCaCertMountPath: "/etc/tls-ca/platform/sef/"
appSefCertMountPath: "/etc/tls/log/sef/"

global:
clientCredentials:
Expand Down
10 changes: 10 additions & 0 deletions eric-oss-hello-world-python-app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ def get_config():
app_key = get_os_env_string("APP_KEY", "")
app_cert = get_os_env_string("APP_CERT", "")
app_cert_file_path = get_os_env_string("APP_CERT_FILE_PATH", "")
app_sef_key = get_os_env_string("APP_SEF_KEY", "")
app_sef_cert = get_os_env_string("APP_SEF_CERT", "")
app_sef_cert_file_path = get_os_env_string("APP_SEF_CERT_FILE_PATH", "")
client_creds_file_path = get_os_env_string("CLIENT_CREDS_FILE_PATH", "")
client_id_file_name = get_os_env_string("CLIENT_ID_FILE_NAME", "")
ca_sef_cert_file_name = get_os_env_string("CA_SEF_CERT_FILE_NAME", "")
ca_sef_cert_file_path = get_os_env_string("CA_SEF_CERT_FILE_PATH", "")

config = {
"iam_client_id": iam_client_id,
Expand All @@ -31,6 +36,11 @@ def get_config():
"app_cert_file_path": app_cert_file_path,
"client_creds_file_path": client_creds_file_path,
"client_id_file_name": client_id_file_name,
"app_sef_key": app_sef_key,
"app_sef_cert": app_sef_cert,
"app_sef_cert_file_path": app_sef_cert_file_path,
"ca_sef_cert_file_name": ca_sef_cert_file_name,
"ca_sef_cert_file_path": ca_sef_cert_file_path,
}
return config

Expand Down
6 changes: 3 additions & 3 deletions eric-oss-hello-world-python-app/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def login():
login_path = "/auth/realms/master/protocol/openid-connect/token"
login_url = urljoin(config.get("iam_base_url"), login_path)
headers = {"Content-Type": "application/x-www-form-urlencoded"}
resp = tls_login(login_url, headers)
resp = mtls_login(login_url, headers)
resp = json.loads(resp.decode("utf-8"))
token, time_until_expiry = resp["access_token"], resp["expires_in"]
time_until_expiry -= (
Expand All @@ -33,8 +33,8 @@ def login():
return token, time.time() + time_until_expiry


def tls_login(url, headers):
"""This function sends an HTTP POST request with TLS for the login operation"""
def mtls_login(url, headers):
"""This function sends an HTTP POST request with mTLS for the login operation"""
config = get_config()
ca_cert = os.path.join(
"/", config.get("ca_cert_file_path"), config.get("ca_cert_file_name")
Expand Down
23 changes: 21 additions & 2 deletions eric-oss-hello-world-python-app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
along with a health check and metrics endpoints.
"""
import time
import os
import ssl

from flask import abort
from flask import Flask
from login import login
Expand All @@ -17,6 +20,7 @@
CollectorRegistry,
Counter,
)
from config import get_config

SERVICE_PREFIX = "python_hello_world"

Expand Down Expand Up @@ -91,6 +95,21 @@ def create_metrics(self):
self.registry.register(self.requests_failed)


if __name__ == "__main__":
if __name__ == '__main__':
instance = Application()
instance.run(host="0.0.0.0", port="8050")

config = get_config()

# Build paths from config
ca_sef_cert = os.path.join("/", config.get("ca_sef_cert_file_path"), config.get("ca_sef_cert_file_name"))
app_sef_cert = os.path.join("/", config.get("app_sef_cert_file_path"), config.get("app_sef_cert"))
app_sef_key = os.path.join("/", config.get("app_sef_cert_file_path"), config.get("app_sef_key"))

# Create SSL context configured for mTLS
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.load_cert_chain(certfile=app_sef_cert, keyfile=app_sef_key)
ssl_context.load_verify_locations(cafile=ca_sef_cert)
ssl_context.verify_mode = ssl.CERT_REQUIRED

# Start the application with SSL
instance.run(host='0.0.0.0', port=8050, ssl_context=ssl_context)
47 changes: 47 additions & 0 deletions eric-oss-hello-world-python-app/tests/test_mtls_logging.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Tests which cover the app's logging, both to STDOUT and to Log Aggregator"""

import builtins
import json
from unittest import mock
import requests
from mtls_logging import MtlsLogging, Severity
Expand Down Expand Up @@ -60,3 +62,48 @@ def send_log(message, logger_level, log_level):
"""Send a log through the MTLS logger"""
logger = MtlsLogging(logger_level)
logger.log(message, log_level)

def test_log_handles_invalid_url(caplog):
"""Ensure logger logs an error if requests.post raises InvalidURL"""
message = "Test message for InvalidURL"
with mock.patch.object(requests, "post", side_effect=requests.exceptions.InvalidURL("Bad URL")):
logger = MtlsLogging(Severity.DEBUG)
logger.log(message, Severity.CRITICAL)
assert "Request failed for mTLS logging: Bad URL" in caplog.text


def test_log_handles_missing_schema(caplog):
"""Ensure logger logs an error if requests.post raises MissingSchema"""
message = "Test message for MissingSchema"
with mock.patch.object(requests, "post", side_effect=requests.exceptions.MissingSchema("Missing schema")):
logger = MtlsLogging(Severity.DEBUG)
logger.log(message, Severity.CRITICAL)
assert "Request failed for mTLS logging: Missing schema" in caplog.text


def test_init_sets_log_level_from_log_ctrl_file():
# Sample log control file contents with container mapping
log_ctrl_data = [
{"container": "test-container", "severity": "critical"},
{"container": "other-container", "severity": "warning"},
]
log_ctrl_json = json.dumps(log_ctrl_data)

# Mocked config dict including the log_ctrl_file path
mock_config = {
"log_ctrl_file": "/dummy/path/logcontrol.json",
"ca_cert_file_name": "ca.pem",
"ca_cert_file_path": "certs",
"app_cert": "appcert.pem",
"app_key": "appkey.pem",
"app_cert_file_path": "certs",
"log_endpoint": "log.endpoint"
}

# Patch config and environment variable
with mock.patch("mtls_logging.get_config", return_value=mock_config), \
mock.patch("mtls_logging.get_os_env_string", return_value="test-container"), \
mock.patch("builtins.open", mock.mock_open(read_data=log_ctrl_json)):

logger = MtlsLogging(level=None)
assert logger.logger.level == Severity.CRITICAL