diff options
author | Redouane Kachach <rkachach@ibm.com> | 2024-07-02 17:28:40 +0200 |
---|---|---|
committer | Redouane Kachach <rkachach@ibm.com> | 2024-08-14 13:53:08 +0200 |
commit | 677affcbf548cb2a432695e824b9cd8c2a70dbe1 (patch) | |
tree | 5061f1c9354174a8a984856b08f7d4d831ed75cc /src/cephadm | |
parent | Merge PR #58500 into main (diff) | |
download | ceph-677affcbf548cb2a432695e824b9cd8c2a70dbe1.tar.xz ceph-677affcbf548cb2a432695e824b9cd8c2a70dbe1.zip |
mgr/cephadm: adding oauth2-proxy cephadm service
adding new oauth2-proxy service. The enable_auth flag enables SSO
authentication via the oauth2-proxy service. The user must ensure the
oauth2-proxy service is deployed before enabling this flag in the
mgmt-gateway service.
FQDN related changes: previously, we were obtaining the FQDN using a
call to the Python socket library run inside the container. While this
generally works, the FQDN returned inside a container can sometimes
differ from the one obtained outside the container. This discrepancy
could cause some issues. To ensure consistency, we now use the FQDN
from the inventory, which provides the correct value as recognized on the host.
Signed-off-by: Redouane Kachach <rkachach@ibm.com>
Diffstat (limited to 'src/cephadm')
-rwxr-xr-x | src/cephadm/cephadm.py | 11 | ||||
-rw-r--r-- | src/cephadm/cephadmlib/constants.py | 1 | ||||
-rw-r--r-- | src/cephadm/cephadmlib/daemons/__init__.py | 2 | ||||
-rw-r--r-- | src/cephadm/cephadmlib/daemons/oauth2_proxy.py | 165 |
4 files changed, 179 insertions, 0 deletions
diff --git a/src/cephadm/cephadm.py b/src/cephadm/cephadm.py index 5c0762f8bf3..2ec1015f9d2 100755 --- a/src/cephadm/cephadm.py +++ b/src/cephadm/cephadm.py @@ -178,6 +178,7 @@ from cephadmlib.daemons import ( SMB, SNMPGateway, MgmtGateway, + OAuth2Proxy, Tracing, NodeProxy, ) @@ -230,6 +231,7 @@ def get_supported_daemons(): supported_daemons.append(CephadmAgent.daemon_type) supported_daemons.append(SNMPGateway.daemon_type) supported_daemons.append(MgmtGateway.daemon_type) + supported_daemons.append(OAuth2Proxy.daemon_type) supported_daemons.extend(Tracing.components) supported_daemons.append(NodeProxy.daemon_type) supported_daemons.append(SMB.daemon_type) @@ -468,6 +470,8 @@ def update_default_image(ctx: CephadmContext) -> None: ctx.image = SNMPGateway.default_image if type_ == MgmtGateway.daemon_type: ctx.image = MgmtGateway.default_image + if type_ == OAuth2Proxy.daemon_type: + ctx.image = OAuth2Proxy.default_image if type_ == CephNvmeof.daemon_type: ctx.image = CephNvmeof.default_image if type_ in Tracing.components: @@ -864,6 +868,10 @@ def create_daemon_dirs( cg = MgmtGateway.init(ctx, fsid, ident.daemon_id) cg.create_daemon_dirs(data_dir, uid, gid) + elif daemon_type == OAuth2Proxy.daemon_type: + co = OAuth2Proxy.init(ctx, fsid, ident.daemon_id) + co.create_daemon_dirs(data_dir, uid, gid) + elif daemon_type == NodeProxy.daemon_type: node_proxy = NodeProxy.init(ctx, fsid, ident.daemon_id) node_proxy.create_daemon_dirs(data_dir, uid, gid) @@ -3603,6 +3611,9 @@ def list_daemons( elif daemon_type == MgmtGateway.daemon_type: version = MgmtGateway.get_version(ctx, container_id) seen_versions[image_id] = version + elif daemon_type == OAuth2Proxy.daemon_type: + version = OAuth2Proxy.get_version(ctx, container_id) + seen_versions[image_id] = version else: logger.warning('version for unknown daemon type %s' % daemon_type) else: diff --git a/src/cephadm/cephadmlib/constants.py b/src/cephadm/cephadmlib/constants.py index 06163d06489..b104a98bc56 100644 --- a/src/cephadm/cephadmlib/constants.py +++ b/src/cephadm/cephadmlib/constants.py @@ -20,6 +20,7 @@ DEFAULT_JAEGER_AGENT_IMAGE = 'quay.io/jaegertracing/jaeger-agent:1.29' DEFAULT_JAEGER_QUERY_IMAGE = 'quay.io/jaegertracing/jaeger-query:1.29' DEFAULT_SMB_IMAGE = 'quay.io/samba.org/samba-server:devbuilds-centos-amd64' DEFAULT_NGINX_IMAGE = 'quay.io/ceph/nginx:1.26.1' +DEFAULT_OAUTH2_PROXY_IMAGE = 'quay.io/oauth2-proxy/oauth2-proxy:v7.6.0' DEFAULT_REGISTRY = 'docker.io' # normalize unqualified digests to this # ------------------------------------------------------------------------------ diff --git a/src/cephadm/cephadmlib/daemons/__init__.py b/src/cephadm/cephadmlib/daemons/__init__.py index 279f6f1a898..bdf2c532e02 100644 --- a/src/cephadm/cephadmlib/daemons/__init__.py +++ b/src/cephadm/cephadmlib/daemons/__init__.py @@ -10,6 +10,7 @@ from .snmp import SNMPGateway from .tracing import Tracing from .node_proxy import NodeProxy from .mgmt_gateway import MgmtGateway +from .oauth2_proxy import OAuth2Proxy __all__ = [ 'Ceph', @@ -27,4 +28,5 @@ __all__ = [ 'Tracing', 'NodeProxy', 'MgmtGateway', + 'OAuth2Proxy', ] diff --git a/src/cephadm/cephadmlib/daemons/oauth2_proxy.py b/src/cephadm/cephadmlib/daemons/oauth2_proxy.py new file mode 100644 index 00000000000..2b61df9d2e7 --- /dev/null +++ b/src/cephadm/cephadmlib/daemons/oauth2_proxy.py @@ -0,0 +1,165 @@ +import logging +import os +from typing import Dict, List, Tuple, Optional +import re + +from ..call_wrappers import call, CallVerbosity +from ..container_daemon_form import ContainerDaemonForm, daemon_to_container +from ..container_types import CephContainer +from ..context import CephadmContext +from ..context_getters import fetch_configs +from ..daemon_form import register as register_daemon_form +from ..daemon_identity import DaemonIdentity +from ..deployment_utils import to_deployment_container +from ..constants import DEFAULT_OAUTH2_PROXY_IMAGE, UID_NOBODY, GID_NOGROUP +from ..data_utils import dict_get, is_fsid +from ..file_utils import populate_files, makedirs, recursive_chown +from ..exceptions import Error + + +logger = logging.getLogger() + + +@register_daemon_form +class OAuth2Proxy(ContainerDaemonForm): + """Define the configs for the jaeger tracing containers""" + + default_image = DEFAULT_OAUTH2_PROXY_IMAGE + daemon_type = 'oauth2-proxy' + required_files = [ + 'oauth2-proxy.conf', + 'oauth2-proxy.crt', + 'oauth2-proxy.key', + ] + + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return cls.daemon_type == daemon_type + + def __init__( + self, + ctx: CephadmContext, + fsid: str, + daemon_id: str, + config_json: Dict, + image: str = DEFAULT_OAUTH2_PROXY_IMAGE, + ): + self.ctx = ctx + self.fsid = fsid + self.daemon_id = daemon_id + self.image = image + self.files = dict_get(config_json, 'files', {}) + self.validate() + + @classmethod + def init( + cls, ctx: CephadmContext, fsid: str, daemon_id: str + ) -> 'OAuth2Proxy': + return cls(ctx, fsid, daemon_id, fetch_configs(ctx), ctx.image) + + @classmethod + def create( + cls, ctx: CephadmContext, ident: DaemonIdentity + ) -> 'OAuth2Proxy': + return cls.init(ctx, ident.fsid, ident.daemon_id) + + @property + def identity(self) -> DaemonIdentity: + return DaemonIdentity(self.fsid, self.daemon_type, self.daemon_id) + + def container(self, ctx: CephadmContext) -> CephContainer: + ctr = daemon_to_container(ctx, self) + return to_deployment_container(ctx, ctr) + + def uid_gid(self, ctx: CephadmContext) -> Tuple[int, int]: + return UID_NOBODY, GID_NOGROUP + + def get_daemon_args(self) -> List[str]: + return [ + '--config=/etc/oauth2-proxy.conf', + '--tls-cert-file=/etc/oauth2-proxy.crt', + '--tls-key-file=/etc/oauth2-proxy.key', + ] + + def default_entrypoint(self) -> str: + return '' + + def create_daemon_dirs(self, data_dir: str, uid: int, gid: int) -> None: + """Create files under the container data dir""" + if not os.path.isdir(data_dir): + raise OSError('data_dir is not a directory: %s' % (data_dir)) + logger.info('Writing oauth2-proxy config...') + config_dir = os.path.join(data_dir, 'etc/') + makedirs(config_dir, uid, gid, 0o755) + recursive_chown(config_dir, uid, gid) + populate_files(config_dir, self.files, uid, gid) + + def validate(self) -> None: + if not is_fsid(self.fsid): + raise Error(f'not an fsid: {self.fsid}') + if not self.daemon_id: + raise Error(f'invalid daemon_id: {self.daemon_id}') + if not self.image: + raise Error(f'invalid image: {self.image}') + + # check for the required files + if self.required_files: + for fname in self.required_files: + if fname not in self.files: + raise Error( + 'required file missing from config-json: %s' % fname + ) + + @staticmethod + def get_version(ctx: CephadmContext, container_id: str) -> Optional[str]: + """Return the version of the oauth2-proxy container""" + version = None + out, err, code = call( + ctx, + [ + ctx.container_engine.path, + 'exec', + container_id, + 'oauth2-proxy', + '--version', + ], + verbosity=CallVerbosity.QUIET, + ) + if code == 0: + match = re.search(r'oauth2-proxy (v\d+\.\d+\.\d+)', out) + if match: + version = match.group(1) + return version + + def customize_container_mounts( + self, ctx: CephadmContext, mounts: Dict[str, str] + ) -> None: + data_dir = self.identity.data_dir(ctx.data_dir) + mounts.update( + { + os.path.join( + data_dir, 'etc/oauth2-proxy.conf' + ): '/etc/oauth2-proxy.conf:Z', + os.path.join( + data_dir, 'etc/oauth2-proxy.crt' + ): '/etc/oauth2-proxy.crt:Z', + os.path.join( + data_dir, 'etc/oauth2-proxy.key' + ): '/etc/oauth2-proxy.key:Z', + } + ) + + def customize_container_args( + self, ctx: CephadmContext, args: List[str] + ) -> None: + uid, _ = self.uid_gid(ctx) + other_args = [ + '--user', + str(uid), + ] + args.extend(other_args) + + def customize_process_args( + self, ctx: CephadmContext, args: List[str] + ) -> None: + args.extend(self.get_daemon_args()) |