outposts: allow externally managed SSH Config for outposts (#2917)
This commit is contained in:
		| @ -15,7 +15,7 @@ from yaml import safe_dump | |||||||
|  |  | ||||||
| from authentik import __version__ | from authentik import __version__ | ||||||
| from authentik.outposts.controllers.base import BaseClient, BaseController, ControllerException | from authentik.outposts.controllers.base import BaseClient, BaseController, ControllerException | ||||||
| from authentik.outposts.docker_ssh import DockerInlineSSH | from authentik.outposts.docker_ssh import DockerInlineSSH, SSHManagedExternallyException | ||||||
| from authentik.outposts.docker_tls import DockerInlineTLS | from authentik.outposts.docker_tls import DockerInlineTLS | ||||||
| from authentik.outposts.managed import MANAGED_OUTPOST | from authentik.outposts.managed import MANAGED_OUTPOST | ||||||
| from authentik.outposts.models import ( | from authentik.outposts.models import ( | ||||||
| @ -35,6 +35,7 @@ class DockerClient(UpstreamDockerClient, BaseClient): | |||||||
|     def __init__(self, connection: DockerServiceConnection): |     def __init__(self, connection: DockerServiceConnection): | ||||||
|         self.tls = None |         self.tls = None | ||||||
|         self.ssh = None |         self.ssh = None | ||||||
|  |         self.logger = get_logger() | ||||||
|         if connection.local: |         if connection.local: | ||||||
|             # Same result as DockerClient.from_env |             # Same result as DockerClient.from_env | ||||||
|             super().__init__(**kwargs_from_env()) |             super().__init__(**kwargs_from_env()) | ||||||
| @ -42,8 +43,12 @@ class DockerClient(UpstreamDockerClient, BaseClient): | |||||||
|             parsed_url = urlparse(connection.url) |             parsed_url = urlparse(connection.url) | ||||||
|             tls_config = False |             tls_config = False | ||||||
|             if parsed_url.scheme == "ssh": |             if parsed_url.scheme == "ssh": | ||||||
|  |                 try: | ||||||
|                     self.ssh = DockerInlineSSH(parsed_url.hostname, connection.tls_authentication) |                     self.ssh = DockerInlineSSH(parsed_url.hostname, connection.tls_authentication) | ||||||
|                     self.ssh.write() |                     self.ssh.write() | ||||||
|  |                 except SSHManagedExternallyException as exc: | ||||||
|  |                     # SSH config is managed externally | ||||||
|  |                     self.logger.info(f"SSH Managed externally: {exc}") | ||||||
|             else: |             else: | ||||||
|                 self.tls = DockerInlineTLS( |                 self.tls = DockerInlineTLS( | ||||||
|                     verification_kp=connection.tls_verification, |                     verification_kp=connection.tls_verification, | ||||||
| @ -57,7 +62,6 @@ class DockerClient(UpstreamDockerClient, BaseClient): | |||||||
|                 ) |                 ) | ||||||
|             except SSHException as exc: |             except SSHException as exc: | ||||||
|                 raise ServiceConnectionInvalid from exc |                 raise ServiceConnectionInvalid from exc | ||||||
|         self.logger = get_logger() |  | ||||||
|         # Ensure the client actually works |         # Ensure the client actually works | ||||||
|         self.containers.list() |         self.containers.list() | ||||||
|  |  | ||||||
|  | |||||||
| @ -16,6 +16,10 @@ def opener(path, flags): | |||||||
|     return os.open(path, flags, 0o700) |     return os.open(path, flags, 0o700) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class SSHManagedExternallyException(DockerException): | ||||||
|  |     """Raised when the ssh config file is managed externally.""" | ||||||
|  |  | ||||||
|  |  | ||||||
| class DockerInlineSSH: | class DockerInlineSSH: | ||||||
|     """Create paramiko ssh config from CertificateKeyPair""" |     """Create paramiko ssh config from CertificateKeyPair""" | ||||||
|  |  | ||||||
| @ -29,9 +33,15 @@ class DockerInlineSSH: | |||||||
|     def __init__(self, host: str, keypair: CertificateKeyPair) -> None: |     def __init__(self, host: str, keypair: CertificateKeyPair) -> None: | ||||||
|         self.host = host |         self.host = host | ||||||
|         self.keypair = keypair |         self.keypair = keypair | ||||||
|  |         self.config_path = Path("~/.ssh/config").expanduser() | ||||||
|  |         if self.config_path.exists() and HEADER not in self.config_path.read_text(encoding="utf-8"): | ||||||
|  |             # SSH Config file already exists and there's no header from us, meaning that it's | ||||||
|  |             # been externally mapped into the container for more complex configs | ||||||
|  |             raise SSHManagedExternallyException( | ||||||
|  |                 "SSH Config exists and does not contain authentik header" | ||||||
|  |             ) | ||||||
|         if not self.keypair: |         if not self.keypair: | ||||||
|             raise DockerException("keypair must be set for SSH connections") |             raise DockerException("keypair must be set for SSH connections") | ||||||
|         self.config_path = Path("~/.ssh/config").expanduser() |  | ||||||
|         self.header = f"{HEADER} - {self.host}\n" |         self.header = f"{HEADER} - {self.host}\n" | ||||||
|  |  | ||||||
|     def write_config(self, key_path: str) -> bool: |     def write_config(self, key_path: str) -> bool: | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jens L
					Jens L