# Copyright 2018 Datawire. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License from typing import TYPE_CHECKING from ..config import Config from .irresource import IRResource as IRResource from .irtlscontext import IRTLSContext if TYPE_CHECKING: from .ir import IR # pragma: no cover ############################################################################# ## tls.py -- the tls_context configuration object for Ambassador ## ## IRAmbassadorTLS represents an Ambassador TLS configuration: it's the way ## we unify the TLS module and the 'tls' block in the Ambassador module. This ## class is pretty much all about managing priority between the two -- any ## important information here gets turned into IRTLSContext objects before ## TLS configuration actually happens. ## ## There's a fair amount of logic around making priority decisions between ## the 'tls' block and the TLS module at present. Probably that logic should ## migrate here, or this class should go away. class IRAmbassadorTLS(IRResource): def __init__( self, ir: "IR", aconf: Config, rkey: str = "ir.tlsmodule", kind: str = "IRTLSModule", name: str = "ir.tlsmodule", enabled: bool = True, **kwargs ) -> None: """ Initialize an IRAmbassadorTLS from the raw fields of its Resource. """ ir.logger.debug("IRAmbassadorTLS __init__ (%s %s %s)" % (kind, name, kwargs)) super().__init__( ir=ir, aconf=aconf, rkey=rkey, kind=kind, name=name, enabled=enabled, **kwargs ) class TLSModuleFactory: @classmethod def load_all(cls, ir: "IR", aconf: Config) -> None: assert ir tls_module = aconf.get_module("tls") if tls_module: # ir.logger.debug("TLSModuleFactory saving TLS module: %s" % tls_module.as_json()) # XXX What a hack. IRAmbassadorTLS.from_resource() should be able to make # this painless. new_args = dict(tls_module.as_dict()) new_rkey = new_args.pop("rkey", tls_module.rkey) new_kind = new_args.pop("kind", tls_module.kind) new_name = new_args.pop("name", tls_module.name) new_location = new_args.pop("location", tls_module.location) ir.tls_module = IRAmbassadorTLS( ir, aconf, rkey=new_rkey, kind=new_kind, name=new_name, location=new_location, **new_args ) ir.logger.debug("TLSModuleFactory saved TLS module: %s" % ir.tls_module.as_json()) # Next, a TLS module in the Ambassador module overrides any other TLS Module. amod = aconf.get_module("ambassador") if amod: ir.ambassador_module.sourced_by(amod) ir.ambassador_module.referenced_by(amod) amod_tls = amod.get("tls", None) # Check for an Ambassador module tls field so that we can warn the user that this field is deprecated! if amod_tls: ir.post_error( "The 'tls' field on the Ambassador module is deprecated! Please use a TLSContext instead https://www.getambassador.io/docs/edge-stack/latest/topics/running/tls/#tlscontext" ) # Finally, if we have a TLS Module, turn it into a TLSContext. if ir.tls_module: ir.logger.debug("TLSModuleFactory translating TLS module to TLSContext") # Stash a sane rkey and location for contexts we create. ctx_rkey = ir.tls_module.get("rkey", ir.ambassador_module.rkey) ctx_location = ir.tls_module.get("location", ir.ambassador_module.location) # The TLS module 'server' and 'client' blocks are actually a _single_ TLSContext # to Ambassador. server = ir.tls_module.pop("server", None) client = ir.tls_module.pop("client", None) if server and server.get("enabled", True): # We have a server half. Excellent. ctx = IRTLSContext.from_legacy( ir, "server", ctx_rkey, ctx_location, cert=server, termination=True, validation_ca=client, ) if ctx.is_active(): ir.save_tls_context(ctx) # Other blocks in the TLS module weren't ever really documented, so I seriously doubt # that they're a factor... but, weirdly, we have a test for them... for legacy_name, legacy_ctx in ir.tls_module.as_dict().items(): if ( legacy_name.startswith("_") or (legacy_name == "name") or (legacy_name == "namespace") or (legacy_name == "metadata_labels") or (legacy_name == "location") or (legacy_name == "kind") or (legacy_name == "enabled") ): continue ctx = IRTLSContext.from_legacy( ir, legacy_name, ctx_rkey, ctx_location, cert=legacy_ctx, termination=False, validation_ca=None, ) if ctx.is_active(): ir.save_tls_context(ctx) @classmethod def finalize(cls, ir: "IR", aconf: Config) -> None: pass