Remove client_secret from config, add env var (#1918)

This commit is contained in:
Joe Ranweiler
2022-05-09 16:58:15 -07:00
committed by GitHub
parent f5ce5b3d6f
commit 25405b0b27
4 changed files with 31 additions and 15 deletions

View File

@ -14,7 +14,6 @@ def main(req: func.HttpRequest) -> func.HttpResponse:
endpoint=os.environ.get("ONEFUZZ_ENDPOINT"), endpoint=os.environ.get("ONEFUZZ_ENDPOINT"),
authority=os.environ.get("ONEFUZZ_AUTHORITY"), authority=os.environ.get("ONEFUZZ_AUTHORITY"),
client_id=os.environ.get("ONEFUZZ_CLIENT_ID"), client_id=os.environ.get("ONEFUZZ_CLIENT_ID"),
client_secret=os.environ.get("ONEFUZZ_CLIENT_SECRET"),
) )
info = o.info.get() info = o.info.get()
return func.HttpResponse(info.json()) return func.HttpResponse(info.json())

View File

@ -53,6 +53,9 @@ REPRO_SSH_FORWARD = "1337:127.0.0.1:1337"
UUID_RE = r"^[a-f0-9]{8}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{12}\Z" UUID_RE = r"^[a-f0-9]{8}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{12}\Z"
# Environment variable optionally used for setting an application client secret.
CLIENT_SECRET_ENV_VAR = "ONEFUZZ_CLIENT_SECRET" # nosec
class PreviewFeature(Enum): class PreviewFeature(Enum):
job_templates = "job_templates" job_templates = "job_templates"
@ -1639,11 +1642,22 @@ class Utils(Command):
class Onefuzz: class Onefuzz:
def __init__( def __init__(
self, config_path: Optional[str] = None, token_path: Optional[str] = None self,
config_path: Optional[str] = None,
token_path: Optional[str] = None,
client_secret: Optional[str] = None,
) -> None: ) -> None:
self.logger = logging.getLogger("onefuzz") self.logger = logging.getLogger("onefuzz")
if client_secret is None:
# If not explicitly provided, check the environment for a user-provided client secret.
client_secret = self._client_secret_from_env()
self._backend = Backend( self._backend = Backend(
config=DEFAULT, config_path=config_path, token_path=token_path config=DEFAULT,
config_path=config_path,
token_path=token_path,
client_secret=client_secret,
) )
self.containers = Containers(self) self.containers = Containers(self)
self.repro = Repro(self) self.repro = Repro(self)
@ -1670,6 +1684,12 @@ class Onefuzz:
self.__setup__() self.__setup__()
# Try to obtain a confidential client secret from the environment.
#
# If not set, return `None`.
def _client_secret_from_env(self) -> Optional[str]:
return os.environ.get(CLIENT_SECRET_ENV_VAR)
def __setup__( def __setup__(
self, self,
endpoint: Optional[str] = None, endpoint: Optional[str] = None,
@ -1686,7 +1706,7 @@ class Onefuzz:
if client_id is not None: if client_id is not None:
self._backend.config.client_id = client_id self._backend.config.client_id = client_id
if client_secret is not None: if client_secret is not None:
self._backend.config.client_secret = client_secret self._backend.client_secret = client_secret
if tenant_domain is not None: if tenant_domain is not None:
self._backend.config.tenant_domain = tenant_domain self._backend.config.tenant_domain = tenant_domain
@ -1730,7 +1750,6 @@ class Onefuzz:
endpoint: Optional[str] = None, endpoint: Optional[str] = None,
authority: Optional[str] = None, authority: Optional[str] = None,
client_id: Optional[str] = None, client_id: Optional[str] = None,
client_secret: Optional[str] = None,
enable_feature: Optional[PreviewFeature] = None, enable_feature: Optional[PreviewFeature] = None,
tenant_domain: Optional[str] = None, tenant_domain: Optional[str] = None,
reset: Optional[bool] = None, reset: Optional[bool] = None,
@ -1759,8 +1778,6 @@ class Onefuzz:
self._backend.config.authority = authority self._backend.config.authority = authority
if client_id is not None: if client_id is not None:
self._backend.config.client_id = client_id self._backend.config.client_id = client_id
if client_secret is not None:
self._backend.config.client_secret = client_secret
if enable_feature: if enable_feature:
self._backend.enable_feature(enable_feature.name) self._backend.enable_feature(enable_feature.name)
if tenant_domain is not None: if tenant_domain is not None:
@ -1769,9 +1786,6 @@ class Onefuzz:
self._backend.save_config() self._backend.save_config()
data = self._backend.config.copy(deep=True) data = self._backend.config.copy(deep=True)
if data.client_secret is not None:
# replace existing secrets with "*** for user display
data.client_secret = "***" # nosec
if not data.endpoint: if not data.endpoint:
self.logger.warning("endpoint not configured yet") self.logger.warning("endpoint not configured yet")

View File

@ -88,7 +88,6 @@ def check_application_error(response: requests.Response) -> None:
class BackendConfig(BaseModel): class BackendConfig(BaseModel):
authority: str authority: str
client_id: str client_id: str
client_secret: Optional[str]
endpoint: Optional[str] endpoint: Optional[str]
features: Set[str] = Field(default_factory=set) features: Set[str] = Field(default_factory=set)
tenant_domain: Optional[str] tenant_domain: Optional[str]
@ -100,9 +99,11 @@ class Backend:
config: BackendConfig, config: BackendConfig,
config_path: Optional[str] = None, config_path: Optional[str] = None,
token_path: Optional[str] = None, token_path: Optional[str] = None,
client_secret: Optional[str] = None,
): ):
self.config_path = os.path.expanduser(config_path or DEFAULT_CONFIG_PATH) self.config_path = os.path.expanduser(config_path or DEFAULT_CONFIG_PATH)
self.token_path = os.path.expanduser(token_path or DEFAULT_TOKEN_PATH) self.token_path = os.path.expanduser(token_path or DEFAULT_TOKEN_PATH)
self.client_secret = client_secret
self.config = config self.config = config
self.token_cache: Optional[msal.SerializableTokenCache] = None self.token_cache: Optional[msal.SerializableTokenCache] = None
self.init_cache() self.init_cache()
@ -187,16 +188,17 @@ class Backend:
f"https://{netloc}/.default", # before 3.0.0 release f"https://{netloc}/.default", # before 3.0.0 release
] ]
if self.config.client_secret: if self.client_secret:
return self.client_secret(scopes) return self.access_token_from_client_secret(scopes)
return self.device_login(scopes) return self.device_login(scopes)
def client_secret(self, scopes: List[str]) -> Any: def access_token_from_client_secret(self, scopes: List[str]) -> Any:
if not self.app: if not self.app:
self.app = msal.ConfidentialClientApplication( self.app = msal.ConfidentialClientApplication(
self.config.client_id, self.config.client_id,
authority=self.config.authority, authority=self.config.authority,
client_credential=self.config.client_secret, client_credential=self.client_secret,
token_cache=self.token_cache, token_cache=self.token_cache,
) )

View File

@ -45,6 +45,7 @@ JMES_HELP = (
) )
# Call `Onefuzz.setup()`, which enables overriding configuration and authentication parameters.
def call_setup(api: Any, args: argparse.Namespace) -> None: def call_setup(api: Any, args: argparse.Namespace) -> None:
setup = getattr(api, "__setup__", None) setup = getattr(api, "__setup__", None)
if setup is None: if setup is None: