def _get_contract_token_from_cloud_identity(cfg: config.UAConfig) -> str: """Detect cloud_type and request a contract token from identity info. :param cfg: a ``config.UAConfig`` instance :raise NonAutoAttachImageError: When not on an auto-attach image type. :raise UrlError: On unexpected connectivity issues to contract server or inability to access identity doc from metadata service. :raise ContractAPIError: On unexpected errors when talking to the contract server. :return: contract token obtained from identity doc """ cloud_type = identity.get_cloud_type() if cloud_type not in ("aws", ): # TODO(avoid hard-coding supported types) raise exceptions.NonAutoAttachImageError( ua_status.MESSAGE_UNSUPPORTED_AUTO_ATTACH_CLOUD_TYPE.format( cloud_type=cloud_type)) instance = identity.cloud_instance_factory() contract_client = contract.UAContractClient(cfg) pkcs7 = instance.identity_doc try: # TODO(make this logic cloud-agnostic if possible) tokenResponse = contract_client.request_aws_contract_token(pkcs7) except contract.ContractAPIError as e: if contract.API_ERROR_MISSING_INSTANCE_INFORMATION in e: raise exceptions.NonAutoAttachImageError( ua_status.MESSAGE_UNSUPPORTED_AUTO_ATTACH) raise e return tokenResponse["contractToken"]
def _inform_ubuntu_pro_existence_if_applicable() -> None: """Alert the user when running UA on cloud with PRO support.""" cloud_type, _ = get_cloud_type() if cloud_type in PRO_CLOUDS: print( messages.SECURITY_USE_PRO_TMPL.format( title=CLOUD_TYPE_TO_TITLE.get(cloud_type), cloud=cloud_type ) )
def _perform_enable(self, silent: bool = False) -> bool: cloud_type, error = get_cloud_type() if cloud_type is None and error == NoCloudTypeReason.CLOUD_ID_ERROR: logging.warning( "Could not determine cloud, " "defaulting to generic FIPS package." ) if super()._perform_enable(silent=silent): self.cfg.remove_notice("", messages.FIPS_INSTALL_OUT_OF_DATE) return True return False
def static_affordances(self) -> Tuple[StaticAffordance, ...]: cloud_titles = {"aws": "an AWS", "azure": "an Azure", "gce": "a GCP"} cloud_id, _ = get_cloud_type() if cloud_id is None: cloud_id = "" series = util.get_platform_info().get("series", "") blocked_message = messages.FIPS_BLOCK_ON_CLOUD.format( series=series.title(), cloud=cloud_titles.get(cloud_id) ) return ( ( blocked_message, lambda: self._allow_fips_on_cloud_instance(series, cloud_id), True, ), )
def _replace_metapackage_on_cloud_instance( self, packages: List[str] ) -> List[str]: """ Identify correct metapackage to be used if in a cloud instance. Currently, the contract backend is not delivering the right metapackage on a Bionic Azure or AWS cloud instance. For those clouds, we have cloud specific fips metapackages and we should use them. We are now performing that correction here, but this is a temporary fix. """ cfg_disable_fips_metapackage_override = util.is_config_value_true( config=self.cfg.cfg, path_to_value="features.disable_fips_metapackage_override", ) if cfg_disable_fips_metapackage_override: return packages series = util.get_platform_info().get("series") if series not in ("bionic", "focal"): return packages cloud_id, _ = get_cloud_type() if cloud_id is None: cloud_id = "" cloud_match = re.match(r"^(?P<cloud>(azure|aws|gce)).*", cloud_id) cloud_id = cloud_match.group("cloud") if cloud_match else "" if cloud_id not in ("azure", "aws", "gce"): return packages cloud_id = "gcp" if cloud_id == "gce" else cloud_id cloud_metapkg = "ubuntu-{}-fips".format(cloud_id) # Replace only the ubuntu-fips meta package if exists return [ cloud_metapkg if pkg == "ubuntu-fips" else pkg for pkg in packages ]
def apply_contract_overrides(orig_access: Dict[str, Any], series: Optional[str] = None) -> None: """Apply series-specific overrides to an entitlement dict. This function mutates orig_access dict by applying any series-overrides to the top-level keys under 'entitlement'. The series-overrides are sparse and intended to supplement existing top-level dict values. So, sub-keys under the top-level directives, obligations and affordance sub-key values will be preserved if unspecified in series-overrides. To more clearly indicate that orig_access in memory has already had the overrides applied, the 'series' key is also removed from the orig_access dict. :param orig_access: Dict with original entitlement access details """ from uaclient.clouds.identity import get_cloud_type if not all([isinstance(orig_access, dict), "entitlement" in orig_access]): raise RuntimeError( 'Expected entitlement access dict. Missing "entitlement" key:' " {}".format(orig_access)) series_name = get_platform_info()["series"] if series is None else series cloud_type, _ = get_cloud_type() orig_entitlement = orig_access.get("entitlement", {}) overrides = _select_overrides(orig_entitlement, series_name, cloud_type) for _weight, overrides_to_apply in sorted(overrides.items()): for key, value in overrides_to_apply.items(): current = orig_access["entitlement"].get(key) if isinstance(current, dict): # If the key already exists and is a dict, # update that dict using the override current.update(value) else: # Otherwise, replace it wholesale orig_access["entitlement"][key] = value
def test_fallback_if_no_cloud_type_found(self, m_cloud_type_from_result_file, m_which): assert get_cloud_type() is None
def test_fallback_to_get_cloud_type_from_result_file( self, m_subp, m_cloud_type_from_result_file): """Use cloud-id utility to discover cloud type.""" assert "cloud9" == get_cloud_type() assert [mock.call()] == m_cloud_type_from_result_file.call_args_list
def test_use_cloud_id_when_available(self, m_subp, m_which): """Use cloud-id utility to discover cloud type.""" assert "somecloud" == get_cloud_type() assert [mock.call("cloud-id")] == m_which.call_args_list