mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-15 03:18:07 +00:00
Config Refactor Round 2. (#2771)
* Config Refactor Round 2. * Adding docs. * Fix file formatting. * Removing. * fixing imports. * Removing. * Fixing cli access token retrieval. * Fixing authority check. * Small edits. * Removing duplicate. * Adding uuid check. * Possible to override with existing params. * Allowing flags to override storage. * Trying to fix config params.? * Fixing. * Set endpoint params via app function. * Checking changes to params. * Make tenant_domain default. * Remove endoint params from models. * UPdating docs. * Setting * Removing hardcoded values. * Typo. * Removing endpoint upload. * Typo. * Fixing typos. * Fix error message about aad tenant. * Responding to comments. * Update src/ApiService/ApiService/UserCredentials.cs Co-authored-by: Marc Greisen <mgreisen@microsoft.com> --------- Co-authored-by: Marc Greisen <mgreisen@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
3d2fb65c14
commit
f402304084
34
src/ApiService/ApiService/Functions/Config.cs
Normal file
34
src/ApiService/ApiService/Functions/Config.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Microsoft.Azure.Functions.Worker;
|
||||||
|
using Microsoft.Azure.Functions.Worker.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.OneFuzz.Service.Functions;
|
||||||
|
|
||||||
|
public class Config {
|
||||||
|
private readonly ILogTracer _log;
|
||||||
|
private readonly IOnefuzzContext _context;
|
||||||
|
|
||||||
|
public Config(ILogTracer log, IOnefuzzContext context) {
|
||||||
|
_log = log;
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Function("Config")]
|
||||||
|
public Async.Task<HttpResponseData> Run(
|
||||||
|
[HttpTrigger(AuthorizationLevel.Anonymous, "GET")] HttpRequestData req) {
|
||||||
|
return Get(req);
|
||||||
|
}
|
||||||
|
public async Async.Task<HttpResponseData> Get(HttpRequestData req) {
|
||||||
|
_log.Info($"getting endpoint config parameters");
|
||||||
|
|
||||||
|
var endpointParams = new ConfigResponse(
|
||||||
|
Authority: _context.ServiceConfiguration.Authority,
|
||||||
|
ClientId: _context.ServiceConfiguration.CliAppId,
|
||||||
|
TenantDomain: _context.ServiceConfiguration.TenantDomain);
|
||||||
|
|
||||||
|
var response = req.CreateResponse(HttpStatusCode.OK);
|
||||||
|
await response.WriteAsJsonAsync(endpointParams);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
@ -159,6 +159,12 @@ public record ScalesetResponse(
|
|||||||
Nodes: null);
|
Nodes: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record ConfigResponse(
|
||||||
|
string? Authority,
|
||||||
|
string? ClientId,
|
||||||
|
string? TenantDomain
|
||||||
|
) : BaseResponse();
|
||||||
|
|
||||||
public class BaseResponseConverter : JsonConverter<BaseResponse> {
|
public class BaseResponseConverter : JsonConverter<BaseResponse> {
|
||||||
public override BaseResponse? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
public override BaseResponse? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -26,7 +26,9 @@ public interface IServiceConfig {
|
|||||||
|
|
||||||
public string? DiagnosticsAzureBlobContainerSasUrl { get; }
|
public string? DiagnosticsAzureBlobContainerSasUrl { get; }
|
||||||
public string? DiagnosticsAzureBlobRetentionDays { get; }
|
public string? DiagnosticsAzureBlobRetentionDays { get; }
|
||||||
|
public string? CliAppId { get; }
|
||||||
|
public string? Authority { get; }
|
||||||
|
public string? TenantDomain { get; }
|
||||||
public string? MultiTenantDomain { get; }
|
public string? MultiTenantDomain { get; }
|
||||||
public ResourceIdentifier? OneFuzzDataStorage { get; }
|
public ResourceIdentifier? OneFuzzDataStorage { get; }
|
||||||
public ResourceIdentifier? OneFuzzFuncStorage { get; }
|
public ResourceIdentifier? OneFuzzFuncStorage { get; }
|
||||||
@ -97,7 +99,9 @@ public class ServiceConfiguration : IServiceConfig {
|
|||||||
|
|
||||||
public string? DiagnosticsAzureBlobContainerSasUrl { get => GetEnv("DIAGNOSTICS_AZUREBLOBCONTAINERSASURL"); }
|
public string? DiagnosticsAzureBlobContainerSasUrl { get => GetEnv("DIAGNOSTICS_AZUREBLOBCONTAINERSASURL"); }
|
||||||
public string? DiagnosticsAzureBlobRetentionDays { get => GetEnv("DIAGNOSTICS_AZUREBLOBRETENTIONINDAYS"); }
|
public string? DiagnosticsAzureBlobRetentionDays { get => GetEnv("DIAGNOSTICS_AZUREBLOBRETENTIONINDAYS"); }
|
||||||
|
public string? CliAppId { get => GetEnv("CLI_APP_ID"); }
|
||||||
|
public string? Authority { get => GetEnv("AUTHORITY"); }
|
||||||
|
public string? TenantDomain { get => GetEnv("TENANT_DOMAIN"); }
|
||||||
public string? MultiTenantDomain { get => GetEnv("MULTI_TENANT_DOMAIN"); }
|
public string? MultiTenantDomain { get => GetEnv("MULTI_TENANT_DOMAIN"); }
|
||||||
|
|
||||||
public ResourceIdentifier? OneFuzzDataStorage {
|
public ResourceIdentifier? OneFuzzDataStorage {
|
||||||
|
@ -92,7 +92,7 @@ public class UserCredentials : IUserCredentials {
|
|||||||
} else {
|
} else {
|
||||||
var tenantsStr = allowedTenants.OkV is null ? "null" : String.Join(';', allowedTenants.OkV!);
|
var tenantsStr = allowedTenants.OkV is null ? "null" : String.Join(';', allowedTenants.OkV!);
|
||||||
_log.Error($"issuer not from allowed tenant. issuer: {token.Issuer:Tag:Issuer} - tenants: {tenantsStr:Tag:Tenants}");
|
_log.Error($"issuer not from allowed tenant. issuer: {token.Issuer:Tag:Issuer} - tenants: {tenantsStr:Tag:Tenants}");
|
||||||
return OneFuzzResult<UserAuthInfo>.Error(ErrorCode.INVALID_REQUEST, new[] { "unauthorized AAD issuer" });
|
return OneFuzzResult<UserAuthInfo>.Error(ErrorCode.INVALID_REQUEST, new[] { "unauthorized AAD issuer. If multi-tenant auth is failing, make sure to include all tenant_ids in the `allowed_aad_tenants` list in the instance_config. To see the current instance_config, run `onefuzz instance_config get`. " });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_log.Error($"Failed to get allowed tenants due to {allowedTenants.ErrorV:Tag:Error}");
|
_log.Error($"Failed to get allowed tenants due to {allowedTenants.ErrorV:Tag:Error}");
|
||||||
|
@ -26,7 +26,7 @@ public class ConfigOperations : Orm<InstanceConfig>, IConfigOperations {
|
|||||||
private static readonly InstanceConfigCacheKey _key = new(); // singleton key
|
private static readonly InstanceConfigCacheKey _key = new(); // singleton key
|
||||||
public Task<InstanceConfig> Fetch()
|
public Task<InstanceConfig> Fetch()
|
||||||
=> _cache.GetOrCreateAsync(_key, async entry => {
|
=> _cache.GetOrCreateAsync(_key, async entry => {
|
||||||
entry = entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(10)); // cached for 10 minutes
|
entry = entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(1)); // cached for 1 minute
|
||||||
var key = _context.ServiceConfiguration.OneFuzzInstanceName ?? throw new Exception("Environment variable ONEFUZZ_INSTANCE_NAME is not set");
|
var key = _context.ServiceConfiguration.OneFuzzInstanceName ?? throw new Exception("Environment variable ONEFUZZ_INSTANCE_NAME is not set");
|
||||||
return await GetEntityAsync(key, key);
|
return await GetEntityAsync(key, key);
|
||||||
});
|
});
|
||||||
|
@ -25,6 +25,11 @@ public sealed class TestServiceConfiguration : IServiceConfig {
|
|||||||
|
|
||||||
public string? OneFuzzTelemetry => "TestOneFuzzTelemetry";
|
public string? OneFuzzTelemetry => "TestOneFuzzTelemetry";
|
||||||
|
|
||||||
|
public string? CliAppId => "TestGuid";
|
||||||
|
|
||||||
|
public string? Authority => "TestAuthority";
|
||||||
|
|
||||||
|
public string? TenantDomain => "TestDomain";
|
||||||
public string? MultiTenantDomain => null;
|
public string? MultiTenantDomain => null;
|
||||||
|
|
||||||
public string? OneFuzzInstanceName => "UnitTestInstance";
|
public string? OneFuzzInstanceName => "UnitTestInstance";
|
||||||
|
@ -41,8 +41,9 @@ from .ssh import build_ssh_command, ssh_connect, temp_file
|
|||||||
UUID_EXPANSION = TypeVar("UUID_EXPANSION", UUID, str)
|
UUID_EXPANSION = TypeVar("UUID_EXPANSION", UUID, str)
|
||||||
|
|
||||||
DEFAULT = BackendConfig(
|
DEFAULT = BackendConfig(
|
||||||
authority="https://login.microsoftonline.com/72f988bf-86f1-41af-91ab-2d7cd011db47",
|
authority="",
|
||||||
client_id="72f1562a-8c0c-41ea-beb9-fa2b71c80134",
|
client_id="",
|
||||||
|
tenant_domain="",
|
||||||
)
|
)
|
||||||
|
|
||||||
# This was generated randomly and should be preserved moving forwards
|
# This was generated randomly and should be preserved moving forwards
|
||||||
@ -122,6 +123,10 @@ class Endpoint:
|
|||||||
as_params: bool = False,
|
as_params: bool = False,
|
||||||
alternate_endpoint: Optional[str] = None,
|
alternate_endpoint: Optional[str] = None,
|
||||||
) -> A:
|
) -> A:
|
||||||
|
|
||||||
|
# Retrieve Auth Parameters
|
||||||
|
self._req_config_params()
|
||||||
|
|
||||||
response = self._req_base(
|
response = self._req_base(
|
||||||
method,
|
method,
|
||||||
data=data,
|
data=data,
|
||||||
@ -153,6 +158,33 @@ class Endpoint:
|
|||||||
|
|
||||||
return [model.parse_obj(x) for x in response]
|
return [model.parse_obj(x) for x in response]
|
||||||
|
|
||||||
|
def _req_config_params(
|
||||||
|
self,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
if self.onefuzz._backend.config.endpoint is None:
|
||||||
|
raise Exception("Endpoint Not Configured")
|
||||||
|
|
||||||
|
endpoint = self.onefuzz._backend.config.endpoint
|
||||||
|
|
||||||
|
response = self.onefuzz._backend.session.request(
|
||||||
|
"GET", endpoint + "/api/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.debug(response.json())
|
||||||
|
endpoint_params = responses.Config.parse_obj(response.json())
|
||||||
|
|
||||||
|
logging.debug(self.onefuzz._backend.config.authority)
|
||||||
|
# Will override values in storage w/ provided values for SP use
|
||||||
|
if self.onefuzz._backend.config.client_id == "":
|
||||||
|
self.onefuzz._backend.config.client_id = endpoint_params.client_id
|
||||||
|
if self.onefuzz._backend.config.authority == "":
|
||||||
|
self.onefuzz._backend.config.authority = endpoint_params.authority
|
||||||
|
if self.onefuzz._backend.config.tenant_domain == "":
|
||||||
|
self.onefuzz._backend.config.tenant_domain = endpoint_params.tenant_domain
|
||||||
|
|
||||||
|
self.onefuzz._backend.save_config()
|
||||||
|
|
||||||
def _disambiguate(
|
def _disambiguate(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
@ -1862,7 +1894,9 @@ class Onefuzz:
|
|||||||
self.logger.debug("set config")
|
self.logger.debug("set config")
|
||||||
|
|
||||||
if reset:
|
if reset:
|
||||||
self._backend.config = BackendConfig(authority="", client_id="")
|
self._backend.config = BackendConfig(
|
||||||
|
authority="", client_id="", tenant_domain=""
|
||||||
|
)
|
||||||
|
|
||||||
if endpoint is not None:
|
if endpoint is not None:
|
||||||
# The normal path for calling the API always uses the oauth2 workflow,
|
# The normal path for calling the API always uses the oauth2 workflow,
|
||||||
|
@ -95,7 +95,7 @@ class BackendConfig(BaseModel):
|
|||||||
client_id: str
|
client_id: 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: str
|
||||||
|
|
||||||
|
|
||||||
class Backend:
|
class Backend:
|
||||||
@ -181,7 +181,7 @@ class Backend:
|
|||||||
if not self.config.endpoint:
|
if not self.config.endpoint:
|
||||||
raise Exception("endpoint not configured")
|
raise Exception("endpoint not configured")
|
||||||
|
|
||||||
if self.config.tenant_domain:
|
if "https://login.microsoftonline.com/common" in self.config.authority:
|
||||||
endpoint = urlparse(self.config.endpoint).netloc.split(".")[0]
|
endpoint = urlparse(self.config.endpoint).netloc.split(".")[0]
|
||||||
scopes = [
|
scopes = [
|
||||||
f"api://{self.config.tenant_domain}/{endpoint}/.default",
|
f"api://{self.config.tenant_domain}/{endpoint}/.default",
|
||||||
|
@ -8,6 +8,9 @@ param clientSecret string
|
|||||||
param signedExpiry string
|
param signedExpiry string
|
||||||
param app_func_issuer string
|
param app_func_issuer string
|
||||||
param app_func_audiences array
|
param app_func_audiences array
|
||||||
|
param cli_app_id string
|
||||||
|
param authority string
|
||||||
|
param tenant_domain string
|
||||||
param multi_tenant_domain string
|
param multi_tenant_domain string
|
||||||
param enable_remote_debugging bool = false
|
param enable_remote_debugging bool = false
|
||||||
param enable_profiler bool = false
|
param enable_profiler bool = false
|
||||||
@ -239,6 +242,9 @@ module functionSettings 'bicep-templates/function-settings.bicep' = {
|
|||||||
fuzz_storage_resource_id: storage.outputs.FuzzId
|
fuzz_storage_resource_id: storage.outputs.FuzzId
|
||||||
keyvault_name: keyVaultName
|
keyvault_name: keyVaultName
|
||||||
monitor_account_name: operationalInsights.outputs.monitorAccountName
|
monitor_account_name: operationalInsights.outputs.monitorAccountName
|
||||||
|
cli_app_id: cli_app_id
|
||||||
|
authority: authority
|
||||||
|
tenant_domain: tenant_domain
|
||||||
multi_tenant_domain: multi_tenant_domain
|
multi_tenant_domain: multi_tenant_domain
|
||||||
enable_profiler: enable_profiler
|
enable_profiler: enable_profiler
|
||||||
app_config_endpoint: featureFlags.outputs.AppConfigEndpoint
|
app_config_endpoint: featureFlags.outputs.AppConfigEndpoint
|
||||||
|
@ -8,6 +8,9 @@ param app_insights_key string
|
|||||||
@secure()
|
@secure()
|
||||||
param func_sas_url string
|
param func_sas_url string
|
||||||
|
|
||||||
|
param cli_app_id string
|
||||||
|
param authority string
|
||||||
|
param tenant_domain string
|
||||||
param multi_tenant_domain string
|
param multi_tenant_domain string
|
||||||
|
|
||||||
@secure()
|
@secure()
|
||||||
@ -37,7 +40,7 @@ resource function 'Microsoft.Web/sites@2021-02-01' existing = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var enable_profilers = enable_profiler ? {
|
var enable_profilers = enable_profiler ? {
|
||||||
APPINSIGHTS_PROFILERFEATURE_VERSION : '1.0.0'
|
APPINSIGHTS_PROFILERFEATURE_VERSION: '1.0.0'
|
||||||
DiagnosticServices_EXTENSION_VERSION: '~3'
|
DiagnosticServices_EXTENSION_VERSION: '~3'
|
||||||
} : {}
|
} : {}
|
||||||
|
|
||||||
@ -52,6 +55,9 @@ resource functionSettings 'Microsoft.Web/sites/config@2021-03-01' = {
|
|||||||
APPINSIGHTS_APPID: app_insights_app_id
|
APPINSIGHTS_APPID: app_insights_app_id
|
||||||
ONEFUZZ_TELEMETRY: telemetry
|
ONEFUZZ_TELEMETRY: telemetry
|
||||||
AzureWebJobsStorage: func_sas_url
|
AzureWebJobsStorage: func_sas_url
|
||||||
|
CLI_APP_ID: cli_app_id
|
||||||
|
AUTHORITY: authority
|
||||||
|
TENANT_DOMAIN: tenant_domain
|
||||||
MULTI_TENANT_DOMAIN: multi_tenant_domain
|
MULTI_TENANT_DOMAIN: multi_tenant_domain
|
||||||
AzureWebJobsDisableHomepage: 'true'
|
AzureWebJobsDisableHomepage: 'true'
|
||||||
AzureSignalRConnectionString: signal_r_connection_string
|
AzureSignalRConnectionString: signal_r_connection_string
|
||||||
@ -66,5 +72,5 @@ resource functionSettings 'Microsoft.Web/sites/config@2021-03-01' = {
|
|||||||
ONEFUZZ_KEYVAULT: keyvault_name
|
ONEFUZZ_KEYVAULT: keyvault_name
|
||||||
ONEFUZZ_OWNER: owner
|
ONEFUZZ_OWNER: owner
|
||||||
ONEFUZZ_CLIENT_SECRET: client_secret
|
ONEFUZZ_CLIENT_SECRET: client_secret
|
||||||
}, enable_profilers)
|
}, enable_profilers)
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ param diagnostics_log_level string
|
|||||||
param log_retention int
|
param log_retention int
|
||||||
param linux_fx_version string
|
param linux_fx_version string
|
||||||
|
|
||||||
|
|
||||||
var siteconfig = (use_windows) ? {
|
var siteconfig = (use_windows) ? {
|
||||||
} : {
|
} : {
|
||||||
linuxFxVersion: linux_fx_version
|
linuxFxVersion: linux_fx_version
|
||||||
@ -57,17 +56,17 @@ resource function 'Microsoft.Web/sites@2021-03-01' = {
|
|||||||
type: 'SystemAssigned'
|
type: 'SystemAssigned'
|
||||||
}
|
}
|
||||||
properties: union({
|
properties: union({
|
||||||
siteConfig: union(siteconfig, commonSiteConfig)
|
siteConfig: union(siteconfig, commonSiteConfig)
|
||||||
httpsOnly: true
|
httpsOnly: true
|
||||||
serverFarmId: server_farm_id
|
serverFarmId: server_farm_id
|
||||||
clientAffinityEnabled: true
|
clientAffinityEnabled: true
|
||||||
}, extraProperties)
|
}, extraProperties)
|
||||||
}
|
}
|
||||||
|
|
||||||
resource funcAuthSettings 'Microsoft.Web/sites/config@2021-03-01' = {
|
resource funcAuthSettings 'Microsoft.Web/sites/config@2021-03-01' = {
|
||||||
name: 'authsettingsV2'
|
name: 'authsettingsV2'
|
||||||
properties: {
|
properties: {
|
||||||
login:{
|
login: {
|
||||||
tokenStore: {
|
tokenStore: {
|
||||||
enabled: true
|
enabled: true
|
||||||
}
|
}
|
||||||
@ -75,6 +74,7 @@ resource funcAuthSettings 'Microsoft.Web/sites/config@2021-03-01' = {
|
|||||||
globalValidation: {
|
globalValidation: {
|
||||||
unauthenticatedClientAction: 'RedirectToLoginPage'
|
unauthenticatedClientAction: 'RedirectToLoginPage'
|
||||||
requireAuthentication: true
|
requireAuthentication: true
|
||||||
|
excludedPaths: [ '/api/config' ]
|
||||||
}
|
}
|
||||||
httpSettings: {
|
httpSettings: {
|
||||||
requireHttps: true
|
requireHttps: true
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"tenant_id": "72f988bf-86f1-41af-91ab-2d7cd011db47",
|
||||||
|
"tenant_domain": "azurewebsites.net",
|
||||||
|
"multi_tenant_domain": "",
|
||||||
|
"cli_client_id": "72f1562a-8c0c-41ea-beb9-fa2b71c80134",
|
||||||
"proxy_nsg_config": {
|
"proxy_nsg_config": {
|
||||||
"allowed_ips": ["*"],
|
"allowed_ips": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
"allowed_service_tags": []
|
"allowed_service_tags": []
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -43,8 +43,9 @@ from azure.storage.blob import (
|
|||||||
from msrest.serialization import TZ_UTC
|
from msrest.serialization import TZ_UTC
|
||||||
|
|
||||||
from deploylib.configuration import (
|
from deploylib.configuration import (
|
||||||
|
Config,
|
||||||
InstanceConfigClient,
|
InstanceConfigClient,
|
||||||
NetworkSecurityConfig,
|
NsgRule,
|
||||||
parse_rules,
|
parse_rules,
|
||||||
update_admins,
|
update_admins,
|
||||||
update_allowed_aad_tenants,
|
update_allowed_aad_tenants,
|
||||||
@ -61,7 +62,6 @@ from deploylib.registration import (
|
|||||||
get_application,
|
get_application,
|
||||||
get_service_principal,
|
get_service_principal,
|
||||||
get_signed_in_user,
|
get_signed_in_user,
|
||||||
get_tenant_id,
|
|
||||||
query_microsoft_graph,
|
query_microsoft_graph,
|
||||||
register_application,
|
register_application,
|
||||||
set_app_audience,
|
set_app_audience,
|
||||||
@ -74,10 +74,6 @@ from deploylib.registration import (
|
|||||||
USER_READ_PERMISSION = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
|
USER_READ_PERMISSION = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
|
||||||
MICROSOFT_GRAPH_APP_ID = "00000003-0000-0000-c000-000000000000"
|
MICROSOFT_GRAPH_APP_ID = "00000003-0000-0000-c000-000000000000"
|
||||||
|
|
||||||
ONEFUZZ_CLI_AUTHORITY = (
|
|
||||||
"https://login.microsoftonline.com/72f988bf-86f1-41af-91ab-2d7cd011db47"
|
|
||||||
)
|
|
||||||
COMMON_AUTHORITY = "https://login.microsoftonline.com/common"
|
|
||||||
TELEMETRY_NOTICE = (
|
TELEMETRY_NOTICE = (
|
||||||
"Telemetry collection on stats and OneFuzz failures are sent to Microsoft. "
|
"Telemetry collection on stats and OneFuzz failures are sent to Microsoft. "
|
||||||
"To disable, delete the ONEFUZZ_TELEMETRY application setting in the "
|
"To disable, delete the ONEFUZZ_TELEMETRY application setting in the "
|
||||||
@ -139,7 +135,7 @@ class Client:
|
|||||||
location: str,
|
location: str,
|
||||||
application_name: str,
|
application_name: str,
|
||||||
owner: str,
|
owner: str,
|
||||||
nsg_config: str,
|
config: str,
|
||||||
client_id: Optional[str],
|
client_id: Optional[str],
|
||||||
client_secret: Optional[str],
|
client_secret: Optional[str],
|
||||||
app_zip: str,
|
app_zip: str,
|
||||||
@ -167,7 +163,7 @@ class Client:
|
|||||||
self.location = location
|
self.location = location
|
||||||
self.application_name = application_name
|
self.application_name = application_name
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
self.nsg_config = nsg_config
|
self.config = config
|
||||||
self.app_zip = app_zip
|
self.app_zip = app_zip
|
||||||
self.tools = tools
|
self.tools = tools
|
||||||
self.instance_specific = instance_specific
|
self.instance_specific = instance_specific
|
||||||
@ -180,10 +176,6 @@ class Client:
|
|||||||
"client_id": client_id,
|
"client_id": client_id,
|
||||||
"client_secret": client_secret,
|
"client_secret": client_secret,
|
||||||
}
|
}
|
||||||
if self.multi_tenant_domain:
|
|
||||||
authority = COMMON_AUTHORITY
|
|
||||||
else:
|
|
||||||
authority = ONEFUZZ_CLI_AUTHORITY
|
|
||||||
self.migrations = migrations
|
self.migrations = migrations
|
||||||
self.export_appinsights = export_appinsights
|
self.export_appinsights = export_appinsights
|
||||||
self.admins = admins
|
self.admins = admins
|
||||||
@ -196,9 +188,15 @@ class Client:
|
|||||||
self.host_dotnet_on_windows = host_dotnet_on_windows
|
self.host_dotnet_on_windows = host_dotnet_on_windows
|
||||||
self.enable_profiler = enable_profiler
|
self.enable_profiler = enable_profiler
|
||||||
|
|
||||||
|
self.rules: List[NsgRule] = []
|
||||||
|
|
||||||
|
self.tenant_id = ""
|
||||||
|
self.tenant_domain = ""
|
||||||
|
self.authority = ""
|
||||||
|
|
||||||
self.cli_config: Dict[str, Union[str, UUID]] = {
|
self.cli_config: Dict[str, Union[str, UUID]] = {
|
||||||
"client_id": self.cli_app_id,
|
"client_id": "",
|
||||||
"authority": authority,
|
"authority": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
machine = platform.machine()
|
machine = platform.machine()
|
||||||
@ -305,7 +303,7 @@ class Client:
|
|||||||
# The url to access the instance
|
# The url to access the instance
|
||||||
# This also represents the legacy identifier_uris of the application
|
# This also represents the legacy identifier_uris of the application
|
||||||
# registration
|
# registration
|
||||||
if self.multi_tenant_domain:
|
if self.multi_tenant_domain != "":
|
||||||
return "https://%s/%s" % (self.multi_tenant_domain, self.application_name)
|
return "https://%s/%s" % (self.multi_tenant_domain, self.application_name)
|
||||||
else:
|
else:
|
||||||
return "https://%s.azurewebsites.net" % self.application_name
|
return "https://%s.azurewebsites.net" % self.application_name
|
||||||
@ -316,14 +314,14 @@ class Client:
|
|||||||
# to be from an approved domain The format of this value is derived
|
# to be from an approved domain The format of this value is derived
|
||||||
# from the default value proposed by azure when creating an application
|
# from the default value proposed by azure when creating an application
|
||||||
# registration api://{guid}/...
|
# registration api://{guid}/...
|
||||||
if self.multi_tenant_domain:
|
if self.multi_tenant_domain != "":
|
||||||
return "api://%s/%s" % (self.multi_tenant_domain, self.application_name)
|
return "api://%s/%s" % (self.multi_tenant_domain, self.application_name)
|
||||||
else:
|
else:
|
||||||
return "api://%s.azurewebsites.net" % self.application_name
|
return "api://%s.azurewebsites.net" % self.application_name
|
||||||
|
|
||||||
def get_signin_audience(self) -> str:
|
def get_signin_audience(self) -> str:
|
||||||
# https://docs.microsoft.com/en-us/azure/active-directory/develop/supported-accounts-validation
|
# https://docs.microsoft.com/en-us/azure/active-directory/develop/supported-accounts-validation
|
||||||
if self.multi_tenant_domain:
|
if self.multi_tenant_domain != "":
|
||||||
return "AzureADMultipleOrgs"
|
return "AzureADMultipleOrgs"
|
||||||
else:
|
else:
|
||||||
return "AzureADMyOrg"
|
return "AzureADMyOrg"
|
||||||
@ -382,7 +380,7 @@ class Client:
|
|||||||
else:
|
else:
|
||||||
self.update_existing_app_registration(app, app_roles)
|
self.update_existing_app_registration(app, app_roles)
|
||||||
|
|
||||||
if self.multi_tenant_domain and app["signInAudience"] == "AzureADMyOrg":
|
if self.multi_tenant_domain != "" and app["signInAudience"] == "AzureADMyOrg":
|
||||||
set_app_audience(
|
set_app_audience(
|
||||||
app["id"],
|
app["id"],
|
||||||
"AzureADMultipleOrgs",
|
"AzureADMultipleOrgs",
|
||||||
@ -419,13 +417,10 @@ class Client:
|
|||||||
OnefuzzAppRole.CliClient,
|
OnefuzzAppRole.CliClient,
|
||||||
self.get_subscription_id(),
|
self.get_subscription_id(),
|
||||||
)
|
)
|
||||||
if self.multi_tenant_domain:
|
|
||||||
authority = COMMON_AUTHORITY
|
|
||||||
else:
|
|
||||||
authority = app_info.authority
|
|
||||||
self.cli_config = {
|
self.cli_config = {
|
||||||
"client_id": app_info.client_id,
|
"client_id": app_info.client_id,
|
||||||
"authority": authority,
|
"authority": self.authority,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
logger.error(
|
logger.error(
|
||||||
@ -437,14 +432,10 @@ class Client:
|
|||||||
else:
|
else:
|
||||||
onefuzz_cli_app = cli_app
|
onefuzz_cli_app = cli_app
|
||||||
authorize_application(uuid.UUID(onefuzz_cli_app["appId"]), app["appId"])
|
authorize_application(uuid.UUID(onefuzz_cli_app["appId"]), app["appId"])
|
||||||
if self.multi_tenant_domain:
|
|
||||||
authority = COMMON_AUTHORITY
|
|
||||||
else:
|
|
||||||
tenant_id = get_tenant_id(self.get_subscription_id())
|
|
||||||
authority = "https://login.microsoftonline.com/%s" % tenant_id
|
|
||||||
self.cli_config = {
|
self.cli_config = {
|
||||||
"client_id": onefuzz_cli_app["appId"],
|
"client_id": onefuzz_cli_app["appId"],
|
||||||
"authority": authority,
|
"authority": self.authority,
|
||||||
}
|
}
|
||||||
|
|
||||||
# ensure replyURLs is set properly
|
# ensure replyURLs is set properly
|
||||||
@ -641,7 +632,7 @@ class Client:
|
|||||||
# Add --custom_domain value to Allowed token audiences setting
|
# Add --custom_domain value to Allowed token audiences setting
|
||||||
if self.custom_domain:
|
if self.custom_domain:
|
||||||
|
|
||||||
if self.multi_tenant_domain:
|
if self.multi_tenant_domain != "":
|
||||||
root_domain = self.multi_tenant_domain
|
root_domain = self.multi_tenant_domain
|
||||||
else:
|
else:
|
||||||
root_domain = "%s.azurewebsites.net" % self.application_name
|
root_domain = "%s.azurewebsites.net" % self.application_name
|
||||||
@ -653,7 +644,7 @@ class Client:
|
|||||||
|
|
||||||
app_func_audiences.extend(custom_domains)
|
app_func_audiences.extend(custom_domains)
|
||||||
|
|
||||||
if self.multi_tenant_domain:
|
if self.multi_tenant_domain != "":
|
||||||
# clear the value in the Issuer Url field:
|
# clear the value in the Issuer Url field:
|
||||||
# https://docs.microsoft.com/en-us/sharepoint/dev/spfx/use-aadhttpclient-enterpriseapi-multitenant
|
# https://docs.microsoft.com/en-us/sharepoint/dev/spfx/use-aadhttpclient-enterpriseapi-multitenant
|
||||||
app_func_issuer = ""
|
app_func_issuer = ""
|
||||||
@ -680,6 +671,9 @@ class Client:
|
|||||||
"clientSecret": {"value": self.results["client_secret"]},
|
"clientSecret": {"value": self.results["client_secret"]},
|
||||||
"app_func_issuer": {"value": app_func_issuer},
|
"app_func_issuer": {"value": app_func_issuer},
|
||||||
"signedExpiry": {"value": expiry},
|
"signedExpiry": {"value": expiry},
|
||||||
|
"cli_app_id": {"value": self.cli_app_id},
|
||||||
|
"authority": {"value": self.authority},
|
||||||
|
"tenant_domain": {"value": self.tenant_domain},
|
||||||
"multi_tenant_domain": multi_tenant_domain,
|
"multi_tenant_domain": multi_tenant_domain,
|
||||||
"workbookData": {"value": self.workbook_data},
|
"workbookData": {"value": self.workbook_data},
|
||||||
"enable_remote_debugging": {"value": self.host_dotnet_on_windows},
|
"enable_remote_debugging": {"value": self.host_dotnet_on_windows},
|
||||||
@ -778,6 +772,38 @@ class Client:
|
|||||||
table_service = TableService(account_name=name, account_key=key)
|
table_service = TableService(account_name=name, account_key=key)
|
||||||
migrate(table_service, self.migrations)
|
migrate(table_service, self.migrations)
|
||||||
|
|
||||||
|
def parse_config(self) -> None:
|
||||||
|
logger.info("parsing config: %s", self.config)
|
||||||
|
|
||||||
|
if self.config:
|
||||||
|
|
||||||
|
with open(self.config, "r") as template_handle:
|
||||||
|
config_template = json.load(template_handle)
|
||||||
|
|
||||||
|
try:
|
||||||
|
config = Config(config_template)
|
||||||
|
self.rules = parse_rules(config)
|
||||||
|
|
||||||
|
## Values provided via the CLI will override what's in the config.json
|
||||||
|
if self.authority == "":
|
||||||
|
self.authority = (
|
||||||
|
"https://login.microsoftonline.com/" + config.tenant_id
|
||||||
|
)
|
||||||
|
if self.tenant_domain == "":
|
||||||
|
self.tenant_domain = config.tenant_domain
|
||||||
|
if self.multi_tenant_domain == "":
|
||||||
|
self.multi_tenant_domain = config.multi_tenant_domain
|
||||||
|
if self.cli_app_id == "":
|
||||||
|
self.cli_app_id = config.cli_client_id
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
logging.info(
|
||||||
|
"An Exception was encountered while parsing config file: %s", ex
|
||||||
|
)
|
||||||
|
raise Exception(
|
||||||
|
"config and sub-values were not properly included in config."
|
||||||
|
)
|
||||||
|
|
||||||
def set_instance_config(self) -> None:
|
def set_instance_config(self) -> None:
|
||||||
logger.info("setting instance config")
|
logger.info("setting instance config")
|
||||||
name = self.results["deploy"]["func_name"]["value"]
|
name = self.results["deploy"]["func_name"]["value"]
|
||||||
@ -787,26 +813,7 @@ class Client:
|
|||||||
|
|
||||||
config_client = InstanceConfigClient(table_service, self.application_name)
|
config_client = InstanceConfigClient(table_service, self.application_name)
|
||||||
|
|
||||||
if self.nsg_config:
|
update_nsg(config_client, self.rules)
|
||||||
logger.info("deploying arm template: %s", self.nsg_config)
|
|
||||||
|
|
||||||
with open(self.nsg_config, "r") as template_handle:
|
|
||||||
config_template = json.load(template_handle)
|
|
||||||
|
|
||||||
try:
|
|
||||||
config = NetworkSecurityConfig(config_template)
|
|
||||||
rules = parse_rules(config)
|
|
||||||
except Exception as ex:
|
|
||||||
logging.info(
|
|
||||||
"An Exception was encountered while parsing nsg_config file: %s", ex
|
|
||||||
)
|
|
||||||
raise Exception(
|
|
||||||
"proxy_nsg_config and sub-values were not properly included in config."
|
|
||||||
+ "Please submit a configuration resembling"
|
|
||||||
+ " { 'proxy_nsg_config': { 'allowed_ips': [], 'allowed_service_tags': [] } }"
|
|
||||||
)
|
|
||||||
|
|
||||||
update_nsg(config_client, rules)
|
|
||||||
|
|
||||||
if self.admins:
|
if self.admins:
|
||||||
update_admins(config_client, self.admins)
|
update_admins(config_client, self.admins)
|
||||||
@ -1136,18 +1143,11 @@ class Client:
|
|||||||
"config",
|
"config",
|
||||||
"--endpoint",
|
"--endpoint",
|
||||||
f"https://{self.application_name}.azurewebsites.net",
|
f"https://{self.application_name}.azurewebsites.net",
|
||||||
"--authority",
|
|
||||||
str(self.cli_config["authority"]),
|
|
||||||
"--client_id",
|
|
||||||
str(self.cli_config["client_id"]),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if "client_secret" in self.cli_config:
|
if "client_secret" in self.cli_config:
|
||||||
cmd += ["--client_secret", "YOUR_CLIENT_SECRET_HERE"]
|
cmd += ["--client_secret", "YOUR_CLIENT_SECRET_HERE"]
|
||||||
|
|
||||||
if self.multi_tenant_domain:
|
|
||||||
cmd += ["--tenant_domain", str(self.multi_tenant_domain)]
|
|
||||||
|
|
||||||
as_str = " ".join(cmd)
|
as_str = " ".join(cmd)
|
||||||
|
|
||||||
logger.info(f"Update your CLI config via: {as_str}")
|
logger.info(f"Update your CLI config via: {as_str}")
|
||||||
@ -1174,6 +1174,7 @@ def lower_case(arg: str) -> str:
|
|||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
rbac_only_states = [
|
rbac_only_states = [
|
||||||
|
("parse_config", Client.parse_config),
|
||||||
("check_region", Client.check_region),
|
("check_region", Client.check_region),
|
||||||
("rbac", Client.setup_rbac),
|
("rbac", Client.setup_rbac),
|
||||||
("eventgrid", Client.remove_eventgrid),
|
("eventgrid", Client.remove_eventgrid),
|
||||||
@ -1200,7 +1201,7 @@ def main() -> None:
|
|||||||
parser.add_argument("resource_group")
|
parser.add_argument("resource_group")
|
||||||
parser.add_argument("application_name", type=lower_case)
|
parser.add_argument("application_name", type=lower_case)
|
||||||
parser.add_argument("owner")
|
parser.add_argument("owner")
|
||||||
parser.add_argument("nsg_config")
|
parser.add_argument("config")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--bicep-template",
|
"--bicep-template",
|
||||||
type=arg_file,
|
type=arg_file,
|
||||||
@ -1272,7 +1273,7 @@ def main() -> None:
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--multi_tenant_domain",
|
"--multi_tenant_domain",
|
||||||
type=str,
|
type=str,
|
||||||
default=None,
|
default="",
|
||||||
help="enable multi-tenant authentication with this tenant domain",
|
help="enable multi-tenant authentication with this tenant domain",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -1299,7 +1300,7 @@ def main() -> None:
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--cli_app_id",
|
"--cli_app_id",
|
||||||
type=str,
|
type=str,
|
||||||
default="72f1562a-8c0c-41ea-beb9-fa2b71c80134",
|
default="",
|
||||||
help="CLI App Registration to be used during deployment.",
|
help="CLI App Registration to be used during deployment.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -1337,7 +1338,7 @@ def main() -> None:
|
|||||||
location=args.location,
|
location=args.location,
|
||||||
application_name=args.application_name,
|
application_name=args.application_name,
|
||||||
owner=args.owner,
|
owner=args.owner,
|
||||||
nsg_config=args.nsg_config,
|
config=args.config,
|
||||||
client_id=args.client_id,
|
client_id=args.client_id,
|
||||||
client_secret=args.client_secret,
|
client_secret=args.client_secret,
|
||||||
app_zip=args.app_zip,
|
app_zip=args.app_zip,
|
||||||
|
@ -48,12 +48,17 @@ class InstanceConfigClient:
|
|||||||
self.enable_storage_client_logging()
|
self.enable_storage_client_logging()
|
||||||
|
|
||||||
|
|
||||||
class NetworkSecurityConfig:
|
class Config:
|
||||||
|
cli_client_id: str
|
||||||
|
tenant_id: str
|
||||||
|
tenant_domain: str
|
||||||
|
multi_tenant_domain: str
|
||||||
allowed_ips: List[str]
|
allowed_ips: List[str]
|
||||||
allowed_service_tags: List[str]
|
allowed_service_tags: List[str]
|
||||||
|
|
||||||
def __init__(self, config: Any):
|
def __init__(self, config: Any):
|
||||||
self.parse_nsg_json(config)
|
self.parse_nsg_json(config)
|
||||||
|
self.parse_endpoint_json(config)
|
||||||
|
|
||||||
def parse_nsg_json(self, config: Any) -> None:
|
def parse_nsg_json(self, config: Any) -> None:
|
||||||
if not isinstance(config, Dict):
|
if not isinstance(config, Dict):
|
||||||
@ -107,6 +112,66 @@ class NetworkSecurityConfig:
|
|||||||
self.allowed_ips = proxy_config["allowed_ips"]
|
self.allowed_ips = proxy_config["allowed_ips"]
|
||||||
self.allowed_service_tags = proxy_config["allowed_service_tags"]
|
self.allowed_service_tags = proxy_config["allowed_service_tags"]
|
||||||
|
|
||||||
|
def parse_endpoint_json(self, config: Any) -> None:
|
||||||
|
|
||||||
|
if "cli_client_id" not in config:
|
||||||
|
raise Exception(
|
||||||
|
"CLI client_id not provided as valid key. Please Provide Valid Config."
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
not isinstance(config["cli_client_id"], str)
|
||||||
|
or config["cli_client_id"] == ""
|
||||||
|
):
|
||||||
|
raise Exception(
|
||||||
|
"client_id is not a string. Please provide valid client_id."
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
UUID(config["cli_client_id"])
|
||||||
|
except ValueError:
|
||||||
|
raise Exception(
|
||||||
|
"client_id is not a valid UUID. Please provide valid client_id."
|
||||||
|
)
|
||||||
|
|
||||||
|
if "tenant_id" not in config:
|
||||||
|
raise Exception(
|
||||||
|
"tenant_id not provided as valid key. Please provide valid config."
|
||||||
|
)
|
||||||
|
|
||||||
|
if not isinstance(config["tenant_id"], str) or config["tenant_id"] == "":
|
||||||
|
raise Exception(
|
||||||
|
"tenant_id is not a string. Please provide valid tenant_id."
|
||||||
|
)
|
||||||
|
|
||||||
|
if "tenant_domain" not in config:
|
||||||
|
raise Exception(
|
||||||
|
"tenant_domain not provided as valid key. Please provide valid config."
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
not isinstance(config["tenant_domain"], str)
|
||||||
|
or config["tenant_domain"] == ""
|
||||||
|
):
|
||||||
|
raise Exception(
|
||||||
|
"tenant_domain is not a string. Please provide valid tenant_domain."
|
||||||
|
)
|
||||||
|
|
||||||
|
if "multi_tenant_domain" not in config:
|
||||||
|
raise Exception(
|
||||||
|
"multi_tenant_domain not provided as valid key. Please provide valid config. If the instance is not multi-tenant, please provide an empty string."
|
||||||
|
)
|
||||||
|
|
||||||
|
if not isinstance(config["multi_tenant_domain"], str):
|
||||||
|
raise Exception(
|
||||||
|
"multi_tenant_domain is not a string. Please provide valid multi_tenant_domain. If the instance is not multi-tenant, please provide an empty string."
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cli_client_id = config["cli_client_id"]
|
||||||
|
self.tenant_id = config["tenant_id"]
|
||||||
|
self.tenant_domain = config["tenant_domain"]
|
||||||
|
self.multi_tenant_domain = config["multi_tenant_domain"]
|
||||||
|
|
||||||
|
|
||||||
class NsgRule:
|
class NsgRule:
|
||||||
rule: str
|
rule: str
|
||||||
@ -175,7 +240,7 @@ def update_admins(config_client: InstanceConfigClient, admins: List[UUID]) -> No
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def parse_rules(proxy_config: NetworkSecurityConfig) -> List[NsgRule]:
|
def parse_rules(proxy_config: Config) -> List[NsgRule]:
|
||||||
|
|
||||||
allowed_ips = proxy_config.allowed_ips
|
allowed_ips = proxy_config.allowed_ips
|
||||||
allowed_service_tags = proxy_config.allowed_service_tags
|
allowed_service_tags = proxy_config.allowed_service_tags
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deploylib.configuration import NetworkSecurityConfig
|
from deploylib.configuration import Config
|
||||||
|
|
||||||
|
|
||||||
class DeployTests(unittest.TestCase):
|
class DeployTests(unittest.TestCase):
|
||||||
@ -15,33 +15,33 @@ class DeployTests(unittest.TestCase):
|
|||||||
# Test Dictionary
|
# Test Dictionary
|
||||||
invalid_config: Any = ""
|
invalid_config: Any = ""
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
NetworkSecurityConfig(invalid_config)
|
Config(invalid_config)
|
||||||
# Test Empty Dic
|
# Test Empty Dic
|
||||||
invalid_config = {}
|
invalid_config = {}
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
NetworkSecurityConfig(invalid_config)
|
Config(invalid_config)
|
||||||
# Test Invalid Outer Keys
|
# Test Invalid Outer Keys
|
||||||
invalid_config = {"": ""}
|
invalid_config = {"": ""}
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
NetworkSecurityConfig(invalid_config)
|
Config(invalid_config)
|
||||||
# Test Inner Dictionary
|
# Test Inner Dictionary
|
||||||
invalid_config = {"proxy_nsg_config": ""}
|
invalid_config = {"proxy_nsg_config": ""}
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
NetworkSecurityConfig(invalid_config)
|
Config(invalid_config)
|
||||||
# Test Inner Keys
|
# Test Inner Keys
|
||||||
invalid_config = {"proxy_nsg_config": {}}
|
invalid_config = {"proxy_nsg_config": {}}
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
NetworkSecurityConfig(invalid_config)
|
Config(invalid_config)
|
||||||
# Test Inner Keys
|
# Test Inner Keys
|
||||||
invalid_config = {"proxy_nsg_config": {"allowed_ips": ""}}
|
invalid_config = {"proxy_nsg_config": {"allowed_ips": ""}}
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
NetworkSecurityConfig(invalid_config)
|
Config(invalid_config)
|
||||||
# Test Inner Dict Values (lists)
|
# Test Inner Dict Values (lists)
|
||||||
invalid_config = {
|
invalid_config = {
|
||||||
"proxy_nsg_config": {"allowed_ips": [], "allowed_service_tags": ""}
|
"proxy_nsg_config": {"allowed_ips": [], "allowed_service_tags": ""}
|
||||||
}
|
}
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
NetworkSecurityConfig(invalid_config)
|
Config(invalid_config)
|
||||||
# Test List Values
|
# Test List Values
|
||||||
invalid_config = {
|
invalid_config = {
|
||||||
"proxy_nsg_config": {
|
"proxy_nsg_config": {
|
||||||
@ -50,19 +50,19 @@ class DeployTests(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
NetworkSecurityConfig(invalid_config)
|
Config(invalid_config)
|
||||||
|
|
||||||
## Test Valid Configs
|
## Test Valid Configs
|
||||||
# Test Empty Lists
|
# Test Empty Lists
|
||||||
valid_config: Any = {
|
valid_config: Any = {
|
||||||
"proxy_nsg_config": {"allowed_ips": [], "allowed_service_tags": []}
|
"proxy_nsg_config": {"allowed_ips": [], "allowed_service_tags": []}
|
||||||
}
|
}
|
||||||
NetworkSecurityConfig(valid_config)
|
Config(valid_config)
|
||||||
# Test Wild Card Lists
|
# Test Wild Card Lists
|
||||||
valid_config = {
|
valid_config = {
|
||||||
"proxy_nsg_config": {"allowed_ips": ["*"], "allowed_service_tags": []}
|
"proxy_nsg_config": {"allowed_ips": ["*"], "allowed_service_tags": []}
|
||||||
}
|
}
|
||||||
NetworkSecurityConfig(valid_config)
|
Config(valid_config)
|
||||||
# Test IPs Lists
|
# Test IPs Lists
|
||||||
valid_config = {
|
valid_config = {
|
||||||
"proxy_nsg_config": {
|
"proxy_nsg_config": {
|
||||||
@ -70,7 +70,7 @@ class DeployTests(unittest.TestCase):
|
|||||||
"allowed_service_tags": [],
|
"allowed_service_tags": [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NetworkSecurityConfig(valid_config)
|
Config(valid_config)
|
||||||
# Test Tags Lists
|
# Test Tags Lists
|
||||||
valid_config = {
|
valid_config = {
|
||||||
"proxy_nsg_config": {
|
"proxy_nsg_config": {
|
||||||
@ -78,7 +78,7 @@ class DeployTests(unittest.TestCase):
|
|||||||
"allowed_service_tags": ["Internet"],
|
"allowed_service_tags": ["Internet"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NetworkSecurityConfig(valid_config)
|
Config(valid_config)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -52,6 +52,12 @@ class Info(BaseResponse):
|
|||||||
insights_instrumentation_key: Optional[str]
|
insights_instrumentation_key: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
class Config(BaseResponse):
|
||||||
|
authority: str
|
||||||
|
client_id: str
|
||||||
|
tenant_domain: str
|
||||||
|
|
||||||
|
|
||||||
class ContainerInfoBase(BaseResponse):
|
class ContainerInfoBase(BaseResponse):
|
||||||
name: str
|
name: str
|
||||||
metadata: Optional[Dict[str, str]]
|
metadata: Optional[Dict[str, str]]
|
||||||
|
Reference in New Issue
Block a user