Keyvault Integration
This commit is contained in:
Родитель
37cf899f43
Коммит
4e474afc97
|
@ -43,6 +43,7 @@
|
|||
},
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceRoot}/WebService/bin/Debug/netcoreapp2.0/Microsoft.Azure.IoTSolutions.AsaManager.WebService.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceRoot}/WebService/bin/Debug/netcoreapp2.0",
|
||||
|
|
|
@ -23,28 +23,38 @@ namespace Microsoft.Azure.IoTSolutions.AsaManager.Services.Runtime
|
|||
private readonly IConfigurationRoot configuration;
|
||||
private readonly ILogger log;
|
||||
|
||||
// Key Vault
|
||||
private KeyVault keyVault;
|
||||
|
||||
// Constants
|
||||
private const string CLIENT_ID = "KeyVault:aadAppId";
|
||||
private const string CLIENT_SECRET = "KeyVault:aadAppSecret";
|
||||
private const string KEY_VAULT_NAME = "KeyVault:name";
|
||||
|
||||
public ConfigData(ILogger logger)
|
||||
{
|
||||
this.log = logger;
|
||||
|
||||
// More info about configuration at
|
||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration
|
||||
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true);
|
||||
this.configuration = configurationBuilder.Build();
|
||||
|
||||
// Set up Key Vault
|
||||
this.SetUpKeyVault();
|
||||
}
|
||||
|
||||
public string GetString(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
var value = this.GetSecrets(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool GetBool(string key, bool defaultValue = false)
|
||||
{
|
||||
var value = this.GetString(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
var value = this.GetSecrets(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
|
||||
var knownTrue = new HashSet<string> { "true", "t", "yes", "y", "1", "-1" };
|
||||
var knownFalse = new HashSet<string> { "false", "f", "no", "n", "0" };
|
||||
|
@ -59,7 +69,7 @@ namespace Microsoft.Azure.IoTSolutions.AsaManager.Services.Runtime
|
|||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(this.GetString(key, defaultValue.ToString()));
|
||||
return Convert.ToInt32(this.GetSecrets(key, defaultValue.ToString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -67,6 +77,45 @@ namespace Microsoft.Azure.IoTSolutions.AsaManager.Services.Runtime
|
|||
}
|
||||
}
|
||||
|
||||
private void SetUpKeyVault()
|
||||
{
|
||||
var clientId = this.GetEnvironmentVariable(CLIENT_ID, string.Empty);
|
||||
var clientSecret = this.GetEnvironmentVariable(CLIENT_SECRET, string.Empty);
|
||||
var keyVaultName = this.GetEnvironmentVariable(KEY_VAULT_NAME, string.Empty);
|
||||
|
||||
// Initailize key vault
|
||||
this.keyVault = new KeyVault(keyVaultName, clientId, clientSecret, this.log);
|
||||
}
|
||||
|
||||
private string GetSecrets(string key, string defaultValue = "")
|
||||
{
|
||||
string value = string.Empty;
|
||||
|
||||
value = this.GetLocalVariable(key, defaultValue);
|
||||
|
||||
// If secrets are not found locally, search in Key-Vault
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
log.Warn($"Value for secret {key} not found in local env. " +
|
||||
$" Trying to get the secret from KeyVault.", () => { });
|
||||
value = this.keyVault.GetSecret(key);
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
private string GetLocalVariable(string key, string defaultValue = "")
|
||||
{
|
||||
return this.configuration.GetValue(key, defaultValue);
|
||||
}
|
||||
|
||||
public string GetEnvironmentVariable(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void ReplaceEnvironmentVariables(ref string value, string defaultValue = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return;
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
using Microsoft.Azure.IoTSolutions.AsaManager.Services.Diagnostics;
|
||||
using Microsoft.Azure.KeyVault;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.AsaManager.Services.Runtime
|
||||
{
|
||||
public class KeyVault {
|
||||
|
||||
// Key Vault details and access
|
||||
private readonly string name;
|
||||
private readonly string clientId;
|
||||
private readonly string clientSecret;
|
||||
private ILogger log;
|
||||
|
||||
// Key Vault Client
|
||||
private readonly KeyVaultClient keyVaultClient;
|
||||
|
||||
// Constants
|
||||
private const string KEY_VAULT_URI = "https://{0}.vault.azure.net/secrets/{1}";
|
||||
|
||||
public KeyVault(
|
||||
string name,
|
||||
string clientId,
|
||||
string clientSecret,
|
||||
ILogger logger)
|
||||
{
|
||||
this.name = name;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.log = logger;
|
||||
this.keyVaultClient = new KeyVaultClient(
|
||||
new KeyVaultClient.AuthenticationCallback(this.GetToken));
|
||||
}
|
||||
|
||||
public string GetSecret(string secretKey)
|
||||
{
|
||||
secretKey = secretKey.Split(':').Last();
|
||||
var uri = string.Format(KEY_VAULT_URI, this.name, secretKey);
|
||||
|
||||
try
|
||||
{
|
||||
return this.keyVaultClient.GetSecretAsync(uri).Result.Value;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.log.Error($"Secret {secretKey} not found in Key Vault.", ()=>{ });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//the method that will be provided to the KeyVaultClient
|
||||
private async Task<string> GetToken(string authority, string resource, string scope)
|
||||
{
|
||||
var authContext = new AuthenticationContext(authority);
|
||||
ClientCredential clientCred = new ClientCredential(this.clientId, this.clientSecret);
|
||||
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
this.log.Debug($"Failed to obtain authentication token from key vault.", () => { });
|
||||
throw new System.InvalidOperationException("Failed to obtain the JWT token");
|
||||
}
|
||||
|
||||
return result.AccessToken;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,5 +14,7 @@
|
|||
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="1.10.0" />
|
||||
<PackageReference Include="Microsoft.Azure.EventHubs.Processor" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.Azure.EventHubs" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.Azure.KeyVault" Version="2.0.6" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -13,18 +13,11 @@
|
|||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:9024/v1/status",
|
||||
"environmentVariables": {
|
||||
"PCS_TELEMETRY_WEBSERVICE_URL": "http://localhost:9004/v1",
|
||||
"PCS_CONFIG_WEBSERVICE_URL": "http://localhost:9005/v1",
|
||||
"PCS_IOTHUBMANAGER_WEBSERVICE_URL": "http://localhost:9002/v1",
|
||||
"PCS_TELEMETRY_DOCUMENTDB_CONNSTRING": "$(PCS_TELEMETRY_DOCUMENTDB_CONNSTRING)",
|
||||
"PCS_TELEMETRY_STORAGE_TYPE": "$(PCS_TELEMETRY_STORAGE_TYPE)",
|
||||
"PCS_ASA_DATA_AZUREBLOB_ACCOUNT": "$(PCS_ASA_DATA_AZUREBLOB_ACCOUNT)",
|
||||
"PCS_ASA_DATA_AZUREBLOB_KEY": "$(PCS_ASA_DATA_AZUREBLOB_KEY)",
|
||||
"PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX": "$(PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX)",
|
||||
"PCS_EVENTHUB_CONNSTRING": "$(PCS_EVENTHUB_CONNSTRING)",
|
||||
"PCS_EVENTHUB_NAME": "$(PCS_EVENTHUB_NAME)"
|
||||
"PCS_KEYVAULT_NAME": "$(PCS_KEYVAULT_NAME)",
|
||||
"PCS_AAD_APPID": "$(PCS_AAD_APPID)",
|
||||
"PCS_AAD_APPSECRET": "$(PCS_AAD_APPSECRET)"
|
||||
},
|
||||
"applicationUrl": "http://localhost:9024/v1/status"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||
using Microsoft.Azure.IoTSolutions.AsaManager.Services.Diagnostics;
|
||||
using Microsoft.Azure.IoTSolutions.AsaManager.Services.Runtime;
|
||||
using Microsoft.Azure.IoTSolutions.AsaManager.WebService.Auth;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// TODO: tests
|
||||
// TODO: handle errors
|
||||
|
@ -30,73 +31,72 @@ namespace Microsoft.Azure.IoTSolutions.AsaManager.WebService.Runtime
|
|||
public class Config : IConfig
|
||||
{
|
||||
private const string APPLICATION_KEY = "AsaManagerService:";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservice_port";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservicePort";
|
||||
|
||||
private const string LOGGING_KEY = APPLICATION_KEY + "Logging:";
|
||||
private const string LOGGING_LOGLEVEL_KEY = LOGGING_KEY + "LogLevel";
|
||||
private const string LOGGING_INCLUDEPROCESSID_KEY = LOGGING_KEY + "IncludeProcessId";
|
||||
private const string LOGGING_DATEFORMAT_KEY = LOGGING_KEY + "DateFormat";
|
||||
private const string LOGGING_BLACKLIST_PREFIX_KEY = LOGGING_KEY + "BWListPrefix";
|
||||
private const string LOGGING_BLACKLIST_SOURCES_KEY = LOGGING_KEY + "BlackListSources";
|
||||
private const string LOGGING_WHITELIST_SOURCES_KEY = LOGGING_KEY + "WhiteListSources";
|
||||
private const string LOGGING_EXTRADIAGNOSTICS_KEY = LOGGING_KEY + "ExtraDiagnostics";
|
||||
private const string LOGGING_EXTRADIAGNOSTICSPATH_KEY = LOGGING_KEY + "ExtraDiagnosticsPath";
|
||||
private const string LOGGING_LOGLEVEL_KEY = LOGGING_KEY + "logLevel";
|
||||
private const string LOGGING_INCLUDEPROCESSID_KEY = LOGGING_KEY + "includeProcessId";
|
||||
private const string LOGGING_DATEFORMAT_KEY = LOGGING_KEY + "dateFormat";
|
||||
private const string LOGGING_BLACKLIST_PREFIX_KEY = LOGGING_KEY + "bwListPrefix";
|
||||
private const string LOGGING_BLACKLIST_SOURCES_KEY = LOGGING_KEY + "blackListSources";
|
||||
private const string LOGGING_WHITELIST_SOURCES_KEY = LOGGING_KEY + "whiteListSources";
|
||||
private const string LOGGING_EXTRADIAGNOSTICS_KEY = LOGGING_KEY + "extraDiagnostics";
|
||||
private const string LOGGING_EXTRADIAGNOSTICSPATH_KEY = LOGGING_KEY + "extraDiagnosticsPath";
|
||||
|
||||
private const string CLIENT_AUTH_KEY = APPLICATION_KEY + "ClientAuth:";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "cors_whitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "auth_type";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "auth_required";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "corsWhitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "authType";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "authRequired";
|
||||
|
||||
private const string JWT_KEY = APPLICATION_KEY + "ClientAuth:JWT:";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowed_algorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "issuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "audience";
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clock_skew_seconds";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowedAlgorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "authIssuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "aadAppId";
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clockSkewSeconds";
|
||||
|
||||
private const string EVENTHUB_KEY = APPLICATION_KEY + "EventHub:";
|
||||
private const string EVENTHUB_CONNECTION_KEY = EVENTHUB_KEY + "connection_string";
|
||||
private const string EVENTHUB_NAME = EVENTHUB_KEY + "name";
|
||||
private const string EVENTHUB_CHECKPOINT_INTERVAL_MS = EVENTHUB_KEY + "checkpoint_interval_msecs";
|
||||
private const string EVENTHUB_CONNECTION_KEY = EVENTHUB_KEY + "messagesEventHubConnectionString";
|
||||
private const string EVENTHUB_NAME = EVENTHUB_KEY + "messagesEventHubName";
|
||||
private const string EVENTHUB_CHECKPOINT_INTERVAL_MS = EVENTHUB_KEY + "checkpointIntervalMsecs";
|
||||
|
||||
private const string BLOB_STORAGE_KEY = APPLICATION_KEY + "BlobStorage:";
|
||||
private const string STORAGE_REFERENCE_DATA_CONTAINER_KEY = BLOB_STORAGE_KEY + "reference_data_container";
|
||||
private const string STORAGE_EVENTHUB_CONTAINER_KEY = BLOB_STORAGE_KEY + "eventhub_container";
|
||||
private const string STORAGE_ACCOUNT_NAME_KEY = BLOB_STORAGE_KEY + "account_name";
|
||||
private const string STORAGE_ACCOUNT_KEY_KEY = BLOB_STORAGE_KEY + "account_key";
|
||||
private const string STORAGE_ACCOUNT_ENDPOINT_KEY = BLOB_STORAGE_KEY + "account_endpoint";
|
||||
private const string STORAGE_DEVICE_GROUPS_FILE_NAME = BLOB_STORAGE_KEY + "reference_data_device_groups_file_name";
|
||||
private const string STORAGE_RULES_FILE_NAME = BLOB_STORAGE_KEY + "reference_data_rules_file_name";
|
||||
private const string STORAGE_DATE_FORMAT = BLOB_STORAGE_KEY + "reference_data_date_format";
|
||||
private const string STORAGE_TIME_FORMAT = BLOB_STORAGE_KEY + "reference_data_time_format";
|
||||
private const string STORAGE_REFERENCE_DATA_CONTAINER_KEY = BLOB_STORAGE_KEY + "referenceDataContainer";
|
||||
private const string STORAGE_EVENTHUB_CONTAINER_KEY = BLOB_STORAGE_KEY + "eventhubContainer";
|
||||
private const string STORAGE_ACCOUNT_NAME_KEY = BLOB_STORAGE_KEY + "storageAccountName";
|
||||
private const string STORAGE_ACCOUNT_KEY_KEY = BLOB_STORAGE_KEY + "storageAccountKey";
|
||||
private const string STORAGE_ACCOUNT_ENDPOINT_KEY = BLOB_STORAGE_KEY + "storageEndpointSuffix";
|
||||
private const string STORAGE_DEVICE_GROUPS_FILE_NAME = BLOB_STORAGE_KEY + "referenceDataDeviceGroupsFileName";
|
||||
private const string STORAGE_RULES_FILE_NAME = BLOB_STORAGE_KEY + "referenceDataRulesFileName";
|
||||
private const string STORAGE_DATE_FORMAT = BLOB_STORAGE_KEY + "referenceDataDateFormat";
|
||||
private const string STORAGE_TIME_FORMAT = BLOB_STORAGE_KEY + "referenceDataTimeFormat";
|
||||
private const string STORAGE_ACCOUNT_ENDPOINT_DEFAULT = "core.windows.net";
|
||||
|
||||
private const string MESSAGES_KEY = APPLICATION_KEY + "MessagesStorage:";
|
||||
private const string MESSAGES_STORAGE_TYPE_KEY = MESSAGES_KEY + "storageType";
|
||||
private const string MESSAGES_STORAGE_TYPE_KEY = MESSAGES_KEY + "telemetryStorageType";
|
||||
|
||||
private const string ALARMS_KEY = APPLICATION_KEY + "AlarmsStorage:";
|
||||
private const string ALARMS_STORAGE_TYPE_KEY = ALARMS_KEY + "storageType";
|
||||
private const string ALARMS_STORAGE_TYPE_KEY = ALARMS_KEY + "alarmsStorageType";
|
||||
|
||||
private const string DEVICE_TELEMETRY_KEY = "DeviceTelemetryService:";
|
||||
private const string DEVICE_TELEMETRY_WEBSERVICE_URL_KEY = DEVICE_TELEMETRY_KEY + "webservice_url";
|
||||
private const string DEVICE_TELEMETRY_WEBSERVICE_TIMEOUT_KEY = DEVICE_TELEMETRY_KEY + "webservice_timeout_msecs";
|
||||
private const string EXTERNAL_DEPENDENCIES_KEY = "ExternalDependencies:";
|
||||
private const string DEVICE_TELEMETRY_WEBSERVICE_URL_KEY = EXTERNAL_DEPENDENCIES_KEY + "telemetryWebServiceUrl";
|
||||
private const string DEVICE_TELEMETRY_WEBSERVICE_TIMEOUT_KEY = EXTERNAL_DEPENDENCIES_KEY + "telemetryWebServiceTimeoutMsecs";
|
||||
|
||||
private const string CONFIG_KEY = "PCSConfigurationService:";
|
||||
private const string CONFIG_WEBSERVICE_URL_KEY = CONFIG_KEY + "webservice_url";
|
||||
private const string CONFIG_WEBSERVICE_TIMEOUT_KEY = CONFIG_KEY + "webservice_timeout_msecs";
|
||||
private const string CONFIG_WEBSERVICE_URL_KEY = EXTERNAL_DEPENDENCIES_KEY + "configWebServiceUrl";
|
||||
private const string CONFIG_WEBSERVICE_TIMEOUT_KEY = EXTERNAL_DEPENDENCIES_KEY + "configWebServiceTimeoutMsecs";
|
||||
|
||||
private const string IOTHUB_MANAGER_KEY = "IoTHubManagerService:";
|
||||
private const string IOTHUB_MANAGER_WEBSERVICE_URL_KEY = IOTHUB_MANAGER_KEY + "webservice_url";
|
||||
private const string IOTHUB_MANAGER_WEBSERVICE_TIMEOUT_KEY = IOTHUB_MANAGER_KEY + "webservice_timeout_msecs";
|
||||
private const string IOTHUB_MANAGER_RETRY_COUNT = IOTHUB_MANAGER_KEY + "retry_count";
|
||||
private const string IOTHUB_MANAGER_INITIAL_RETRY_INTERVAL_MS = IOTHUB_MANAGER_KEY + "initial_retry_interval_msecs";
|
||||
private const string IOTHUB_MANAGER_RETRY_INCREASE_FACTOR = IOTHUB_MANAGER_KEY + "retry_increase_factor";
|
||||
private const string IOTHUB_MANAGER_WEBSERVICE_URL_KEY = EXTERNAL_DEPENDENCIES_KEY + "iothubmanagerWebServiceUrl";
|
||||
private const string IOTHUB_MANAGER_WEBSERVICE_TIMEOUT_KEY = EXTERNAL_DEPENDENCIES_KEY + "iothubmanagerTimeoutMsecs";
|
||||
|
||||
private const string IOTHUB_MANAGER_RETRY_COUNT = EXTERNAL_DEPENDENCIES_KEY + "retryCount";
|
||||
private const string IOTHUB_MANAGER_INITIAL_RETRY_INTERVAL_MS = EXTERNAL_DEPENDENCIES_KEY + "initialRetryIntervalMsecs";
|
||||
private const string IOTHUB_MANAGER_RETRY_INCREASE_FACTOR = EXTERNAL_DEPENDENCIES_KEY + "retryIncreaseFactor";
|
||||
|
||||
// Values common to all the tables (messages and alarms)
|
||||
private const string COSMOSDBSQL_CONNSTRING_KEY = "cosmosdbsql_connstring";
|
||||
private const string COSMOSDBSQL_DATABASE_KEY = "cosmosdbsql_database";
|
||||
private const string COSMOSDBSQL_CONSISTENCY_KEY = "cosmosdbsql_consistency_level";
|
||||
private const string COSMOSDBSQL_COLLECTION_KEY = "cosmosdbsql_collection";
|
||||
private const string COSMOSDBSQL_RUS_KEY = "cosmosdbsql_RUs";
|
||||
private const string COSMOSDBSQL_CONNSTRING_KEY = "documentDBConnectionString";
|
||||
private const string COSMOSDBSQL_DATABASE_KEY = "documentDBDatabase";
|
||||
private const string COSMOSDBSQL_CONSISTENCY_KEY = "documentDBConsistencyLevel";
|
||||
private const string COSMOSDBSQL_COLLECTION_KEY = "documentDBCollection";
|
||||
private const string COSMOSDBSQL_RUS_KEY = "documentDBRUs";
|
||||
|
||||
// Simple keys used internally in this class, these don't appear in the config file
|
||||
private const string MESSAGES = "messages";
|
||||
|
|
|
@ -1,109 +1,109 @@
|
|||
[AsaManagerService]
|
||||
webservice_port = 9024
|
||||
webservicePort = 9024
|
||||
|
||||
|
||||
; Storage where ASA will write telemetry messages
|
||||
; The application is responsible for preparing this storage before the ASA Job starts
|
||||
[AsaManagerService:MessagesStorage]
|
||||
storageType = "${PCS_TELEMETRY_STORAGE_TYPE}"
|
||||
cosmosdbsql_connstring = "${PCS_TELEMETRY_DOCUMENTDB_CONNSTRING}"
|
||||
cosmosdbsql_database = "pcs-iothub-stream"
|
||||
cosmosdbsql_collection = "messages"
|
||||
telemetryStorageType = ""
|
||||
documentDBConnectionString = ""
|
||||
documentDBDatabase = "pcs-iothub-stream"
|
||||
documentDBCollection = "messages"
|
||||
; For telemetry scenarios, eventual consistency is ok
|
||||
cosmosdbsql_consistency_level = "Eventual"
|
||||
documentDBConsistencyLevel = "Eventual"
|
||||
; 2500 => unlimited space - see https://docs.microsoft.com/en-us/azure/cosmos-db/partition-data
|
||||
cosmosdbsql_RUs = 2500
|
||||
documentDBRUs = 2500
|
||||
|
||||
|
||||
; Storage where ASA will write alarms
|
||||
; The application is responsible for preparing this storage before the ASA Job starts
|
||||
[AsaManagerService:AlarmsStorage]
|
||||
storageType = "CosmosDbSql"
|
||||
cosmosdbsql_connstring = "${PCS_TELEMETRY_DOCUMENTDB_CONNSTRING}"
|
||||
cosmosdbsql_database = "pcs-iothub-stream"
|
||||
cosmosdbsql_collection = "alarms"
|
||||
alarmsStorageType = "CosmosDbSql"
|
||||
documentDBConnectionString = ""
|
||||
documentDBdatabase = "pcs-iothub-stream"
|
||||
documentDBcollection = "alarms"
|
||||
; For telemetry scenarios, eventual consistency is ok
|
||||
cosmosdbsql_consistency_level = "Eventual"
|
||||
documentDBconsistencyLevel = "Eventual"
|
||||
; 400 => fixed storage 10GB - see https://docs.microsoft.com/en-us/azure/cosmos-db/partition-data
|
||||
cosmosdbsql_RUs = 400
|
||||
documentDBRUs = 400
|
||||
|
||||
[AsaManagerService:EventHub]
|
||||
; Connection string for event hub
|
||||
connection_string = ${PCS_EVENTHUB_CONNSTRING}
|
||||
messagesEventHubConnectionString =
|
||||
; Name of event hub
|
||||
name = ${PCS_EVENTHUB_NAME}
|
||||
; event hub checkpoint interval in msecs
|
||||
checkpoint_interval_msecs = 60000
|
||||
messagesEventHubName =
|
||||
; event hub checkpoint interval in Msecs
|
||||
checkpointIntervalMsecs = 60000
|
||||
|
||||
[AsaManagerService:BlobStorage]
|
||||
; Blob Storage Container name for ASA reference data
|
||||
reference_data_container="referenceinput"
|
||||
referenceDataContainer="referenceinput"
|
||||
; Blob Storage Container name for Event Hub Checkpoints
|
||||
eventhub_container="eventhub-checkpoints"
|
||||
eventhubContainer="eventhub-checkpoints"
|
||||
; Blob Storage Account Name
|
||||
account_name=${PCS_ASA_DATA_AZUREBLOB_ACCOUNT}
|
||||
storageAccountName=""
|
||||
; Blob Storage Account Key
|
||||
account_key=${PCS_ASA_DATA_AZUREBLOB_KEY}
|
||||
storageAccountKey=""
|
||||
; Blob Storage Endpoint Suffix
|
||||
account_endpoint=${?PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX}
|
||||
storageEndpointSuffix=""
|
||||
; Following parameters create file path for device groups mapping
|
||||
; in blob storage.
|
||||
; File path will be:
|
||||
; {YYYY-MM-DD}/{HH-mm}/{device_groups_file_name}
|
||||
; For ASA file name must be in this format, see:
|
||||
; https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-use-reference-data
|
||||
reference_data_date_format="yyyy-MM-dd"
|
||||
reference_data_time_format="HH-mm"
|
||||
reference_data_device_groups_file_name="devicegroups.csv"
|
||||
reference_data_rules_file_name="rules.json"
|
||||
referenceDataDateFormat="yyyy-MM-dd"
|
||||
referenceDataTimeFormat="HH-mm"
|
||||
referenceDataDeviceGroupsFileName="devicegroups.csv"
|
||||
referenceDataRulesFileName="rules.json"
|
||||
|
||||
|
||||
[AsaManagerService:Logging]
|
||||
; Application log levels: Debug, Info, Warn, Error
|
||||
; Default: Warn
|
||||
LogLevel = "${?PCS_LOG_LEVEL}"
|
||||
logLevel = "${?PCS_LOG_LEVEL}"
|
||||
; Whether to log the ProcessId, true by default
|
||||
IncludeProcessId = true
|
||||
includeProcessId = true
|
||||
; How to format the datetime in the logs
|
||||
; example: DateFormat = "yyyy-MM-dd HH:mm:ss.fff"
|
||||
DateFormat = "yyyy-MM-dd HH:mm:ss.fff"
|
||||
dateFormat = "yyyy-MM-dd HH:mm:ss.fff"
|
||||
; Prefix to add to the items listed in BlackListSources and WhiteListSources
|
||||
; example: BWListPrefix = "Microsoft.Azure.IoTSolutions.AsaManager."
|
||||
BWListPrefix = "Microsoft.Azure.IoTSolutions.AsaManager."
|
||||
bwListPrefix = "Microsoft.Azure.IoTSolutions.AsaManager."
|
||||
; Comma separated list of classes and methods to ignore, i.e. discard logs from
|
||||
; example: BlackListSources = "AsaConfigAgent.Program,HttpClient.*"
|
||||
BlackListSources = ""
|
||||
blackListSources = ""
|
||||
; Comma separated list of classes and methods to include, i.e. discard everything else
|
||||
; example: WhiteListSources = "HttpClient.*"
|
||||
WhiteListSources = ""
|
||||
whiteListSources = ""
|
||||
; Whether to generate extra log files to diagnose the application. This is disk I/O intensive
|
||||
; and most likely affects the overall performance. Enable this option only for development
|
||||
; to get detailed information about the state of each actor and each device.
|
||||
; Default: false
|
||||
ExtraDiagnostics = false
|
||||
extraDiagnostics = false
|
||||
; Folder to store the extra diagnostics. Logging is disabled if the folder cannot
|
||||
; be created or is not writable.
|
||||
ExtraDiagnosticsPath = "/tmp/asa/"
|
||||
extraDiagnosticsPath = "/tmp/asa/"
|
||||
|
||||
|
||||
[AsaManagerService:ClientAuth]
|
||||
; Current auth type, only "JWT" is currently supported.
|
||||
auth_type="JWT"
|
||||
authType="JWT"
|
||||
; This can be changed to false, for example during development,
|
||||
; to allow invalid/missing authorizations.
|
||||
; Default: true
|
||||
auth_required="${?PCS_AUTH_REQUIRED}"
|
||||
authRequired=""
|
||||
; Can be used when running services on multiple hostnames and/or ports
|
||||
; e.g. "{ 'origins': ['*'], 'methods': ['*'], 'headers': ['*'] }" to allow everything.
|
||||
; Comment it or leave it empty to disable CORS.
|
||||
; Default: empty
|
||||
cors_whitelist = "${?PCS_CORS_WHITELIST}"
|
||||
corsWhitelist = ""
|
||||
|
||||
|
||||
[AsaManagerService:ClientAuth:JWT]
|
||||
; Trusted algorithms
|
||||
; Default: RS256, RS384, RS512
|
||||
allowed_algorithms="RS256"
|
||||
allowedAlgorithms="RS256"
|
||||
; Identifies the security token service (STS) that constructs and returns the token.
|
||||
; In the tokens that Azure AD returns, the issuer is sts.windows.net. The GUID in
|
||||
; the Issuer claim value is the tenant ID of the Azure AD directory. The tenant ID
|
||||
|
@ -112,45 +112,47 @@ allowed_algorithms="RS256"
|
|||
; When using Azure Active Directory, the format of the Issuer is:
|
||||
; https://sts.windows.net/<tenant Id>/
|
||||
; example: issuer="https://sts.windows.net/fa01ade2-2365-4dd1-a084-a6ef027090fc/"
|
||||
issuer="${?PCS_AUTH_ISSUER}"
|
||||
authIssuer=""
|
||||
; Used to verify that tokens are issued to be given to this service
|
||||
; Also referenced as "Application Id" and "Resource Id"
|
||||
; example: audience="2814e709-6a0e-4861-9594-d3b6e2b81331"
|
||||
audience="${?PCS_AUTH_AUDIENCE}"
|
||||
aadTenantId=""
|
||||
; When validating the token expiration, allows some clock skew
|
||||
; Default: 2 minutes
|
||||
clock_skew_seconds = 300
|
||||
clockSkewSeconds = 300
|
||||
|
||||
[ExternalDependencies]
|
||||
; The Device Telemetry service is used to retrieve the list
|
||||
; of monitoring rules, which are used to generate ASA Jobs configuration
|
||||
[DeviceTelemetryService]
|
||||
; e.g. http://127.0.0.1:9004/v1/rules
|
||||
webservice_url = ${PCS_TELEMETRY_WEBSERVICE_URL}
|
||||
telemetryWebServiceUrl = ""
|
||||
; timeout value in milliseconds
|
||||
webservice_timeout_msecs = 10000
|
||||
telemetryWebServiceTimeoutMsecs = 10000
|
||||
|
||||
; The Configuration service is used to retrieve the list
|
||||
; of device groups, which are referenced in the monitoring rules
|
||||
[PCSConfigurationService]
|
||||
; e.g. http://127.0.0.1:9005/v1
|
||||
webservice_url = ${PCS_CONFIG_WEBSERVICE_URL}
|
||||
configWebServiceUrl =""
|
||||
; timeout value in milliseconds
|
||||
webservice_timeout_msecs = 10000
|
||||
configWebServiceTimeoutMsecs = 10000
|
||||
|
||||
; The IoT Hub Manager service is used to run device queries,
|
||||
; e.g. to retrieve the list of device IDs in a device group
|
||||
[IoTHubManagerService]
|
||||
; e.g. http://127.0.0.1:9002/v1
|
||||
webservice_url = ${PCS_IOTHUBMANAGER_WEBSERVICE_URL}
|
||||
iothubmanagerWebServiceUrl = ""
|
||||
; timeout value in milliseconds
|
||||
webservice_timeout_msecs = 10000
|
||||
iothubmanagerTimeoutMsecs = 10000
|
||||
; number of retries to attempt before failing
|
||||
retry_count = 5
|
||||
retryCount = 5
|
||||
; initial interval to wait before retrying. Subsequent retries will
|
||||
; increase interval by retry_increase_factor
|
||||
initial_retry_interval_msecs = 750
|
||||
retry_increase_factor = 2
|
||||
initialRetryIntervalMsecs = 750
|
||||
retryIncreaseFactor = 2
|
||||
|
||||
[KeyVault]
|
||||
aadAppId = ${PCS_AAD_APPID}
|
||||
aadAppSecret = ${PCS_AAD_APPSECRET}
|
||||
name = ${PCS_KEYVAULT_NAME}
|
||||
|
||||
; For more information about ASP.NET logging see
|
||||
; https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging
|
||||
|
|
|
@ -16,21 +16,9 @@ run_container() {
|
|||
|
||||
echo "Starting ASA manager ..."
|
||||
docker run -it -p 9024:9024 \
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL \
|
||||
-e PCS_CONFIG_WEBSERVICE_URL \
|
||||
-e PCS_IOTHUBMANAGER_WEBSERVICE_URL \
|
||||
-e PCS_ASA_DATA_AZUREBLOB_ACCOUNT \
|
||||
-e PCS_ASA_DATA_AZUREBLOB_KEY \
|
||||
-e PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX \
|
||||
-e PCS_EVENTHUB_CONNSTRING \
|
||||
-e PCS_EVENTHUB_NAME \
|
||||
-e PCS_AUTH_REQUIRED \
|
||||
-e PCS_CORS_WHITELIST \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_TWIN_READ_WRITE_ENABLED \
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING \
|
||||
-e PCS_TELEMETRY_STORAGE_TYPE \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
"$DOCKER_IMAGE:testing"
|
||||
}
|
||||
|
||||
|
|
|
@ -21,21 +21,9 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
|
|||
:: Start the application
|
||||
echo Starting ASA manager ...
|
||||
docker run -it -p 9024:9024 ^
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL ^
|
||||
-e PCS_CONFIG_WEBSERVICE_URL ^
|
||||
-e PCS_IOTHUBMANAGER_WEBSERVICE_URL ^
|
||||
-e PCS_ASA_DATA_AZUREBLOB_ACCOUNT ^
|
||||
-e PCS_ASA_DATA_AZUREBLOB_KEY ^
|
||||
-e PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX ^
|
||||
-e PCS_EVENTHUB_CONNSTRING ^
|
||||
-e PCS_EVENTHUB_NAME ^
|
||||
-e PCS_AUTH_REQUIRED ^
|
||||
-e PCS_CORS_WHITELIST ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_TWIN_READ_WRITE_ENABLED ^
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING ^
|
||||
-e PCS_TELEMETRY_STORAGE_TYPE ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
%DOCKER_IMAGE%:testing
|
||||
|
||||
:: - - - - - - - - - - - - - -
|
||||
|
|
|
@ -1,64 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# Before checking all the env vars, detect whether secrets, usually encrypted, are available or not.
|
||||
# Secrets are not available when building a pull request, so the script will not check for those.
|
||||
detect_secrets() {
|
||||
SECRETS_AVAILABLE="true"
|
||||
if [[ "$TRAVIS_PULL_REQUEST" != "" && "$TRAVIS_PULL_REQUEST" != "false" ]]; then
|
||||
SECRETS_AVAILABLE="false"
|
||||
echo "Warning: secrets and encrypted variables are not available when testing pull requests."
|
||||
fi
|
||||
}
|
||||
|
||||
detect_secrets
|
||||
|
||||
if [[ -z "PCS_TELEMETRY_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_TELEMETRY_WEBSERVICE_URL environment variable is not defined."
|
||||
if [[ -z "$PCS_KEYVAULT_NAME" ]]; then
|
||||
echo "Error: the PCS_KEYVAULT_NAME environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_CONFIG_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_CONFIG_WEBSERVICE_URL environment variable is not defined."
|
||||
if [[ -z "$PCS_AAD_APPID" ]]; then
|
||||
echo "Error: the PCS_AAD_APPID environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_IOTHUBMANAGER_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_IOTHUBMANAGER_WEBSERVICE_URL environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_ASA_DATA_AZUREBLOB_ACCOUNT" ]]; then
|
||||
echo "Error: the PCS_ASA_DATA_AZUREBLOB_ACCOUNT environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_ASA_DATA_AZUREBLOB_KEY" && "$SECRETS_AVAILABLE" = "true" ]]; then
|
||||
echo "Error: the PCS_ASA_DATA_AZUREBLOB_KEY environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX" ]]; then
|
||||
echo "Error: the PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_EVENTHUB_CONNSTRING" && "$SECRETS_AVAILABLE" = "true" ]]; then
|
||||
echo "Error: the PCS_EVENTHUB_CONNSTRING environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_TELEMETRY_DOCUMENTDB_CONNSTRING" && "$SECRETS_AVAILABLE" = "true" ]]; then
|
||||
echo "Error: the PCS_TELEMETRY_DOCUMENTDB_CONNSTRING environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_EVENTHUB_NAME" ]]; then
|
||||
echo "Error: the PCS_EVENTHUB_NAME environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_TELEMETRY_STORAGE_TYPE" ]]; then
|
||||
echo "Error: the PCS_TELEMETRY_STORAGE_TYPE environment variable is not defined."
|
||||
if [[ -z "$PCS_AAD_APPSECRET" ]]; then
|
||||
echo "Error: the PCS_AAD_APPSECRET environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
@ -2,53 +2,18 @@
|
|||
|
||||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
IF "%PCS_TELEMETRY_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_TELEMETRY_WEBSERVICE_URL environment variable is not defined.
|
||||
IF "%PCS_KEYVAULT_NAME%" == "" (
|
||||
echo Error: the PCS_KEYVAULT_NAME environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_CONFIG_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_CONFIG_WEBSERVICE_URL environment variable is not defined.
|
||||
IF "%PCS_AAD_APPID%" == "" (
|
||||
echo Error: the PCS_AAD_APPID environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_IOTHUBMANAGER_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_IOTHUBMANAGER_WEBSERVICE_URL environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_ASA_DATA_AZUREBLOB_ACCOUNT%" == "" (
|
||||
echo Error: the PCS_ASA_DATA_AZUREBLOB_ACCOUNT environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_ASA_DATA_AZUREBLOB_KEY%" == "" (
|
||||
echo Error: the PCS_ASA_DATA_AZUREBLOB_KEY environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX%" == "" (
|
||||
echo Error: the PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_EVENTHUB_CONNSTRING%" == "" (
|
||||
echo Error: the PCS_EVENTHUB_CONNSTRING environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_TELEMETRY_DOCUMENTDB_CONNSTRING%" == "" (
|
||||
echo Error: the PCS_TELEMETRY_DOCUMENTDB_CONNSTRING environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_EVENTHUB_NAME%" == "" (
|
||||
echo Error: the PCS_EVENTHUB_NAME environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_TELEMETRY_STORAGE_TYPE%" == "" (
|
||||
echo Error: the PCS_TELEMETRY_STORAGE_TYPE environment variable is not defined.
|
||||
IF "%PCS_AAD_APPSECRET%" == "" (
|
||||
echo Error: the PCS_AAD_APPSECRET environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# Prepare the environment variables used by the application.
|
||||
#
|
||||
|
||||
# Endpoint used to retrieve the list of monitoring rules
|
||||
export PCS_TELEMETRY_WEBSERVICE_URL="http://127.0.0.1:9004/v1"
|
||||
|
||||
# Endpoint used to retrieve the list of device groups
|
||||
export PCS_CONFIG_WEBSERVICE_URL="http://127.0.0.1:9005/v1"
|
||||
|
||||
# Endpoint used to retrieve the list of devices in each group
|
||||
export PCS_IOTHUBMANAGER_WEBSERVICE_URL="http://127.0.0.1:9002/v1"
|
||||
|
||||
# Connection details of the Azure Blob where event hub checkpoints and reference data are stored
|
||||
export PCS_ASA_DATA_AZUREBLOB_ACCOUNT="..."
|
||||
export PCS_ASA_DATA_AZUREBLOB_KEY="..."
|
||||
export PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX="..."
|
||||
|
||||
# Event Hub where device notifications are stored
|
||||
# IotHub needs to be set up to send device twin and lifecycle messages to this event hub, see below links
|
||||
# https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-device-twins
|
||||
# https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry
|
||||
export PCS_EVENTHUB_CONNSTRING="Endpoint=sb://....servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=..."
|
||||
# Name of event hub where device notifications are stored
|
||||
export PCS_EVENTHUB_NAME="..."
|
||||
|
||||
# Azure CosmosDb SQL connection string, storage used for telemetry and alarms
|
||||
export PCS_TELEMETRY_DOCUMENTDB_CONNSTRING="AccountEndpoint=https://....documents.azure.com:443/;AccountKey=...;"
|
||||
|
||||
# The storage type for telemetry messages. Default is "tsi". Allowed values: ["cosmosdb", "tsi"]
|
||||
export PCS_TELEMETRY_STORAGE_TYPE="tsi"
|
|
@ -1,32 +0,0 @@
|
|||
:: Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
:: Prepare the environment variables used by the application.
|
||||
::
|
||||
|
||||
:: Endpoint used to retrieve the list of monitoring rules
|
||||
SETX PCS_TELEMETRY_WEBSERVICE_URL "http://127.0.0.1:9004/v1"
|
||||
|
||||
:: Endpoint used to retrieve the list of device groups
|
||||
SETX PCS_CONFIG_WEBSERVICE_URL "http://127.0.0.1:9005/v1"
|
||||
|
||||
:: Endpoint used to retrieve the list of devices in each group
|
||||
SETX PCS_IOTHUBMANAGER_WEBSERVICE_URL "http://127.0.0.1:9002/v1"
|
||||
|
||||
:: Connection details of the Azure Blob where event hub checkpoints and reference data are stored
|
||||
SETX PCS_ASA_DATA_AZUREBLOB_ACCOUNT "..."
|
||||
SETX PCS_ASA_DATA_AZUREBLOB_KEY "..."
|
||||
SETX PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX "..."
|
||||
|
||||
:: Event Hub connections string for where device notifications are stored
|
||||
:: IotHub needs to be set up to send device twin and lifecycle messages to this event hub, see below links
|
||||
:: https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-device-twins
|
||||
:: https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry
|
||||
SETX PCS_EVENTHUB_CONNSTRING "Endpoint=sb://....servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=..."
|
||||
:: Name of event hub where device notifications are stored
|
||||
SETX PCS_EVENTHUB_NAME "..."
|
||||
|
||||
:: Azure CosmosDb SQL connection string, storage used for telemetry and alarms
|
||||
SETX PCS_TELEMETRY_DOCUMENTDB_CONNSTRING "AccountEndpoint=https://....documents.azure.com:443/;AccountKey=...;"
|
||||
|
||||
:: The storage type for telemetry messages. Default is "tsi". Allowed values: ["cosmosdb", "tsi"]
|
||||
SETX PCS_TELEMETRY_STORAGE_TYPE="tsi"
|
|
@ -54,21 +54,9 @@ run_in_sandbox() {
|
|||
|
||||
docker run -it \
|
||||
-p 9024:9024 \
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL \
|
||||
-e PCS_CONFIG_WEBSERVICE_URL \
|
||||
-e PCS_IOTHUBMANAGER_WEBSERVICE_URL \
|
||||
-e PCS_ASA_DATA_AZUREBLOB_ACCOUNT \
|
||||
-e PCS_ASA_DATA_AZUREBLOB_KEY \
|
||||
-e PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX \
|
||||
-e PCS_EVENTHUB_CONNSTRING \
|
||||
-e PCS_EVENTHUB_NAME \
|
||||
-e PCS_AUTH_REQUIRED \
|
||||
-e PCS_CORS_WHITELIST \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_TWIN_READ_WRITE_ENABLED \
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING \
|
||||
-e PCS_TELEMETRY_STORAGE_TYPE \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
-v "$PCS_CACHE/sandbox/.config:/root/.config" \
|
||||
-v "$PCS_CACHE/sandbox/.dotnet:/root/.dotnet" \
|
||||
-v "$PCS_CACHE/sandbox/.nuget:/root/.nuget" \
|
||||
|
|
|
@ -81,21 +81,9 @@ GOTO :Run
|
|||
:: Start the sandbox and run the application
|
||||
docker run -it ^
|
||||
-p 9024:9024 ^
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL ^
|
||||
-e PCS_CONFIG_WEBSERVICE_URL ^
|
||||
-e PCS_IOTHUBMANAGER_WEBSERVICE_URL ^
|
||||
-e PCS_ASA_DATA_AZUREBLOB_ACCOUNT ^
|
||||
-e PCS_ASA_DATA_AZUREBLOB_KEY ^
|
||||
-e PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX ^
|
||||
-e PCS_EVENTHUB_CONNSTRING ^
|
||||
-e PCS_EVENTHUB_NAME ^
|
||||
-e PCS_AUTH_REQUIRED ^
|
||||
-e PCS_CORS_WHITELIST ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_TWIN_READ_WRITE_ENABLED ^
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING ^
|
||||
-e PCS_TELEMETRY_STORAGE_TYPE ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
-v %PCS_CACHE%\sandbox\.config:/root/.config ^
|
||||
-v %PCS_CACHE%\sandbox\.dotnet:/root/.dotnet ^
|
||||
-v %PCS_CACHE%\sandbox\.nuget:/root/.nuget ^
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
# Note: Windows Bash doesn't support shebang extra params
|
||||
set -e
|
||||
|
||||
# Example usage (see "travis help" for more information):
|
||||
# travis help
|
||||
# travis login --pro
|
||||
# travis whoami --pro
|
||||
# travis accounts --pro
|
||||
# travis history
|
||||
# travis monitor --pro
|
||||
# travis settings
|
||||
# travis show
|
||||
# travis status
|
||||
# travis token --pro
|
||||
# travis whatsup --pro
|
||||
|
||||
APP_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )/"
|
||||
cd $APP_HOME
|
||||
|
||||
mkdir -p .travis
|
||||
|
||||
docker run -it \
|
||||
-v $APP_HOME/.travis:/root/.travis \
|
||||
-v $APP_HOME:/opt/code \
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh $*
|
||||
|
||||
set +e
|
|
@ -1,30 +0,0 @@
|
|||
:: Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
:: Example usage (see "travis help" for more information:
|
||||
:: travis help
|
||||
:: travis login --pro
|
||||
:: travis whoami --pro
|
||||
:: travis accounts --pro
|
||||
:: travis history
|
||||
:: travis monitor --pro
|
||||
:: travis settings
|
||||
:: travis show
|
||||
:: travis status
|
||||
:: travis token --pro
|
||||
:: travis whatsup --pro
|
||||
|
||||
:: strlen("\scripts\") => 9
|
||||
SET APP_HOME=%~dp0
|
||||
SET APP_HOME=%APP_HOME:~0,-9%
|
||||
cd %APP_HOME%
|
||||
|
||||
mkdir .travis 2>NUL
|
||||
|
||||
docker run -it ^
|
||||
-v %APP_HOME%\.travis:/root/.travis ^
|
||||
-v %APP_HOME%:/opt/code ^
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh %*
|
||||
|
||||
endlocal
|
|
@ -23,28 +23,38 @@ namespace Microsoft.Azure.IoTSolutions.Auth.Services.Runtime
|
|||
private readonly IConfigurationRoot configuration;
|
||||
private readonly ILogger log;
|
||||
|
||||
// Key Vault
|
||||
private KeyVault keyVault;
|
||||
|
||||
// Constants
|
||||
private const string CLIENT_ID = "KeyVault:aadAppId";
|
||||
private const string CLIENT_SECRET = "KeyVault:aadAppSecret";
|
||||
private const string KEY_VAULT_NAME = "KeyVault:name";
|
||||
|
||||
public ConfigData(ILogger logger)
|
||||
{
|
||||
this.log = logger;
|
||||
|
||||
// More info about configuration at
|
||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration
|
||||
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true);
|
||||
this.configuration = configurationBuilder.Build();
|
||||
|
||||
// Set up Key Vault
|
||||
this.SetUpKeyVault();
|
||||
}
|
||||
|
||||
public string GetString(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
var value = this.GetSecrets(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool GetBool(string key, bool defaultValue = false)
|
||||
{
|
||||
var value = this.GetString(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
var value = this.GetSecrets(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
|
||||
var knownTrue = new HashSet<string> { "true", "t", "yes", "y", "1", "-1" };
|
||||
var knownFalse = new HashSet<string> { "false", "f", "no", "n", "0" };
|
||||
|
@ -59,7 +69,7 @@ namespace Microsoft.Azure.IoTSolutions.Auth.Services.Runtime
|
|||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(this.GetString(key, defaultValue.ToString()));
|
||||
return Convert.ToInt32(this.GetSecrets(key, defaultValue.ToString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -67,6 +77,45 @@ namespace Microsoft.Azure.IoTSolutions.Auth.Services.Runtime
|
|||
}
|
||||
}
|
||||
|
||||
private void SetUpKeyVault()
|
||||
{
|
||||
var clientId = this.GetEnvironmentVariable(CLIENT_ID, string.Empty);
|
||||
var clientSecret = this.GetEnvironmentVariable(CLIENT_SECRET, string.Empty);
|
||||
var keyVaultName = this.GetEnvironmentVariable(KEY_VAULT_NAME, string.Empty);
|
||||
|
||||
// Initailize key vault
|
||||
this.keyVault = new KeyVault(keyVaultName, clientId, clientSecret, this.log);
|
||||
}
|
||||
|
||||
private string GetSecrets(string key, string defaultValue = "")
|
||||
{
|
||||
string value = string.Empty;
|
||||
|
||||
value = this.GetLocalVariables(key, defaultValue);
|
||||
|
||||
// If secrets are not found locally, search in Key-Vault
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
log.Warn($"Value for secret {key} not found in local env. " +
|
||||
$" Trying to get the secret from KeyVault.", () => { });
|
||||
value = this.keyVault.GetSecret(key);
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
private string GetLocalVariables(string key, string defaultValue = "")
|
||||
{
|
||||
return this.configuration.GetValue(key, defaultValue);
|
||||
}
|
||||
|
||||
public string GetEnvironmentVariable(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void ReplaceEnvironmentVariables(ref string value, string defaultValue = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return;
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
using Microsoft.Azure.IoTSolutions.Auth.Services.Diagnostics;
|
||||
using Microsoft.Azure.KeyVault;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.Auth.Services.Runtime
|
||||
{
|
||||
public class KeyVault
|
||||
{
|
||||
|
||||
// Key Vault details and access
|
||||
private readonly string name;
|
||||
private readonly string clientId;
|
||||
private readonly string clientSecret;
|
||||
private ILogger log;
|
||||
|
||||
// Key Vault Client
|
||||
private readonly KeyVaultClient keyVaultClient;
|
||||
|
||||
// Constants
|
||||
private const string KEY_VAULT_URI = "https://{0}.vault.azure.net/secrets/{1}";
|
||||
|
||||
public KeyVault(
|
||||
string name,
|
||||
string clientId,
|
||||
string clientSecret,
|
||||
ILogger logger)
|
||||
{
|
||||
this.name = name;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.log = logger;
|
||||
this.keyVaultClient = new KeyVaultClient(
|
||||
new KeyVaultClient.AuthenticationCallback(this.GetToken));
|
||||
}
|
||||
|
||||
public string GetSecret(string secretKey)
|
||||
{
|
||||
secretKey = secretKey.Split(':').Last();
|
||||
var uri = string.Format(KEY_VAULT_URI, this.name, secretKey);
|
||||
|
||||
try
|
||||
{
|
||||
return this.keyVaultClient.GetSecretAsync(uri).Result.Value;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.log.Error($"Secret {secretKey} not found in Key Vault.", () => { });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//the method that will be provided to the KeyVaultClient
|
||||
private async Task<string> GetToken(string authority, string resource, string scope)
|
||||
{
|
||||
var authContext = new AuthenticationContext(authority);
|
||||
ClientCredential clientCred = new ClientCredential(this.clientId, this.clientSecret);
|
||||
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
this.log.Debug($"Failed to obtain authentication token from key vault.", () => { });
|
||||
throw new System.InvalidOperationException("Failed to obtain the JWT token");
|
||||
}
|
||||
|
||||
return result.AccessToken;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="2.1.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.1.4" />
|
||||
<PackageReference Include="Microsoft.Azure.KeyVault" Version="2.0.6" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="data\policies\roles.json">
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:9001/v1/status",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"PCS_AUTH_AUDIENCE": "${PCS_AUTH_AUDIENCE}",
|
||||
"PCS_AUTH_ISSUER": "${PCS_AUTH_ISSUER}"
|
||||
"PCS_KEYVAULT_NAME": "$(PCS_KEYVAULT_NAME)",
|
||||
"PCS_AAD_APPID": "$(PCS_AAD_APPID)",
|
||||
"PCS_AAD_APPSECRET": "$(PCS_AAD_APPSECRET)"
|
||||
},
|
||||
"applicationUrl": "http://localhost:9001/v1/status"
|
||||
}
|
||||
|
|
|
@ -23,29 +23,29 @@ namespace Microsoft.Azure.IoTSolutions.Auth.WebService.Runtime
|
|||
public class Config : IConfig
|
||||
{
|
||||
private const string APPLICATION_KEY = "AuthService:";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservice_port";
|
||||
private const string JWT_USER_ID_FROM_KEY = APPLICATION_KEY + "extract_userid_from";
|
||||
private const string JWT_NAME_FROM_KEY = APPLICATION_KEY + "extract_name_from";
|
||||
private const string JWT_EMAIL_FROM_KEY = APPLICATION_KEY + "extract_email_from";
|
||||
private const string JWT_ROLES_FROM_KEY = APPLICATION_KEY + "extract_roles_from";
|
||||
private const string POLICIES_FOLDER_KEY = APPLICATION_KEY + "policies_folder";
|
||||
private const string AAD_ENDPOINT_URL = APPLICATION_KEY + "aad_endpoint_url";
|
||||
private const string AAD_TENANT_ID = APPLICATION_KEY + "aad_tenant_id";
|
||||
private const string AAD_APPLICATION_ID = APPLICATION_KEY + "aad_application_id";
|
||||
private const string AAD_APPLICATION_SECRET = APPLICATION_KEY + "aad_application_secret";
|
||||
private const string ARM_ENDPOINT_URL = APPLICATION_KEY + "arm_endpoint_url";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservicePort";
|
||||
private const string JWT_USER_ID_FROM_KEY = APPLICATION_KEY + "extractUserIdFrom";
|
||||
private const string JWT_NAME_FROM_KEY = APPLICATION_KEY + "extractNameFrom";
|
||||
private const string JWT_EMAIL_FROM_KEY = APPLICATION_KEY + "extractEmailFrom";
|
||||
private const string JWT_ROLES_FROM_KEY = APPLICATION_KEY + "extractRolesFrom";
|
||||
private const string POLICIES_FOLDER_KEY = APPLICATION_KEY + "policiesFolder";
|
||||
private const string AAD_ENDPOINT_URL = APPLICATION_KEY + "aadEndpointUrl";
|
||||
private const string AAD_TENANT_ID = APPLICATION_KEY + "aadTenantId";
|
||||
private const string AAD_APPLICATION_ID = APPLICATION_KEY + "aadAppId";
|
||||
private const string AAD_APPLICATION_SECRET = APPLICATION_KEY + "aadAppSecret";
|
||||
private const string ARM_ENDPOINT_URL = APPLICATION_KEY + "armEndpointUrl";
|
||||
|
||||
private const string CLIENT_AUTH_KEY = APPLICATION_KEY + "ClientAuth:";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "cors_whitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "auth_type";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "auth_required";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "corsWhitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "authType";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "authRequired";
|
||||
|
||||
private const string JWT_KEY = APPLICATION_KEY + "ClientAuth:JWT:";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowed_algorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "issuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "audience";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowedAlgorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "authIssuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "aadAppId";
|
||||
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clock_skew_seconds";
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clockSkewSeconds";
|
||||
|
||||
public const string DEFAULT_ARM_ENDPOINT_URL = "https://management.azure.com/";
|
||||
public const string DEFAULT_AAD_ENDPOINT_URL = "https://login.microsoftonline.com/";
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
[AuthService]
|
||||
webservice_port = 9001
|
||||
webservicePort = 9001
|
||||
; The claims to use to get the current user information
|
||||
extract_userid_from="oid"
|
||||
extract_name_from="given_name,family_name"
|
||||
extract_email_from="email"
|
||||
extract_roles_from="roles"
|
||||
extractUserIdFrom="oid"
|
||||
extractNameFrom="given_name,family_name"
|
||||
extractEmailFrom="email"
|
||||
extractRolesFrom="roles"
|
||||
# Note: when running the service with Docker, the content of the `data`
|
||||
# folder can be overridden, e.g. to inject custom policies.
|
||||
policies_folder = ./data/policies/
|
||||
policiesFolder = ./data/policies/
|
||||
; The AAD endpoint url to acquire ARM token for AAD application
|
||||
aad_endpoint_url="${?PCS_AAD_ENDPOINT_URL}"
|
||||
aadEndpointUrl=""
|
||||
; The AAD Tenant Id
|
||||
aad_tenant_id="${?PCS_AAD_TENANT}"
|
||||
aadTenantId=""
|
||||
; The unique Id of AAD application that has already been authorized
|
||||
; to access ARM resources
|
||||
aad_application_id="${?PCS_AUTH_AUDIENCE}"
|
||||
aadAppId=""
|
||||
; The secret of AAD application
|
||||
aad_application_secret="${?PCS_AAD_APPSECRET}"
|
||||
aadAppSecret=""
|
||||
;; Azure Resource Manager endpoint url to get token
|
||||
arm_endpoint_url="${?PCS_ARM_ENDPOINT_URL}"
|
||||
armEndpointUrl=""
|
||||
|
||||
|
||||
[AuthService:ClientAuth]
|
||||
;; Current auth type, only "JWT" is currently supported.
|
||||
auth_type="JWT"
|
||||
authType="JWT"
|
||||
;; This can be changed to false, for example during development,
|
||||
;; to allow invalid/missing authorizations.
|
||||
;; Default: true
|
||||
auth_required="${?PCS_AUTH_REQUIRED}"
|
||||
authRequired=""
|
||||
;; Can be used when running services on multiple hostnames and/or ports
|
||||
;; e.g. "{ 'origins': ['*'], 'methods': ['*'], 'headers': ['*'] }" to allow everything.
|
||||
;; Comment it or leave it empty to disable CORS.
|
||||
;; Default: empty
|
||||
cors_whitelist = "${?PCS_CORS_WHITELIST}"
|
||||
corsWhitelist = ""
|
||||
|
||||
|
||||
[AuthService:ClientAuth:JWT]
|
||||
; Trusted algorithms
|
||||
; Default: RS256, RS384, RS512
|
||||
allowed_algorithms="RS256"
|
||||
allowedAlgorithms="RS256"
|
||||
; Identifies the security token service (STS) that constructs and returns the token.
|
||||
; In the tokens that Azure AD returns, the issuer is sts.windows.net. The GUID in
|
||||
; the Issuer claim value is the tenant ID of the Azure AD directory. The tenant ID
|
||||
|
@ -47,16 +47,20 @@ allowed_algorithms="RS256"
|
|||
; When using Azure Active Directory, the format of the Issuer is:
|
||||
; https://sts.windows.net/<tenant Id>/
|
||||
; example: issuer="https://sts.windows.net/fa01ade2-2365-4dd1-a084-a6ef027090fc/"
|
||||
issuer="${?PCS_AUTH_ISSUER}"
|
||||
authIssuer=""
|
||||
; Used to verify that tokens are issued to be given to this service
|
||||
; Also referenced as "Application Id" and "Resource Id"
|
||||
; example: audience="2814e709-6a0e-4861-9594-d3b6e2b81331"
|
||||
audience="${?PCS_AUTH_AUDIENCE}"
|
||||
aadAppId=""
|
||||
;; secret of the application audience
|
||||
; When validating the token expiration, allows some clock skew
|
||||
; Default: 2 minutes
|
||||
clock_skew_seconds = 300
|
||||
clockSkewSeconds = 300
|
||||
|
||||
[KeyVault]
|
||||
aadAppId = ${PCS_AAD_APPID}
|
||||
aadAppSecret = ${PCS_AAD_APPSECRET}
|
||||
name = ${PCS_KEYVAULT_NAME}
|
||||
|
||||
; For more information about ASP.NET logging see
|
||||
; https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging
|
||||
|
@ -64,7 +68,7 @@ clock_skew_seconds = 300
|
|||
; internal logs generated by ASP.NET
|
||||
; ASP.NET log levels: Trace, Debug, Information, Warning, Error, Critical
|
||||
[Logging]
|
||||
IncludeScopes = true
|
||||
includeScopes = true
|
||||
LogLevel:Default = "Warning"
|
||||
LogLevel:System = "Warning"
|
||||
LogLevel:Microsoft = "Warning"
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
AUTH_SERVER_URL=""
|
||||
RESOURCE_TYPE=""
|
||||
AUTH_TOKEN=""
|
||||
|
||||
# Acquires auth token for authroizating against key vault.
|
||||
_acquire_token() {
|
||||
__set_keyvault_auth_server
|
||||
|
||||
local _value=$(curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=$PCS_AAD_APPID&resource=https%3A%2F%2Fvault.azure.net&client_secret=$PCS_AAD_APPSECRET&grant_type=client_credentials" $AUTH_SERVER_URL/oauth2/token)
|
||||
AUTH_TOKEN=$(__parse_json $_value "access_token")
|
||||
}
|
||||
|
||||
# Fetch key vault secret.
|
||||
_get_keyvault_secret() {
|
||||
|
||||
# Get a new token each time you access key vault.
|
||||
_acquire_token
|
||||
|
||||
_keyvault_secret_bundle=$(curl -H "Authorization: Bearer $AUTH_TOKEN" -L https://$PCS_KEYVAULT_NAME.vault.azure.net/secrets/$1/?api-version=7.0)
|
||||
_keyvault_secret_bundle="'$_keyvault_secret_bundle'"
|
||||
|
||||
# return the secret value.
|
||||
echo $(__parse_json $_keyvault_secret_bundle "value")
|
||||
}
|
||||
|
||||
# Gets keyvault auth server by examining response headers of unauthenticated request to key vault.
|
||||
# The 401 redirect contains WWW-Authenticate header which has KV auth server and resource type.
|
||||
__set_keyvault_auth_server() {
|
||||
|
||||
# Bare (unauthenticated) request to get secret.
|
||||
key_vault_wo_auth_call=$(curl -i https://$PCS_KEYVAULT_NAME.vault.azure.net/secrets/authEnabled/?api-version=7.0 | grep 'www.*')
|
||||
|
||||
wo_auth_call_resp_header=${key_vault_wo_auth_call#*:}
|
||||
|
||||
# Extract auth server (url) & resource from WWW-Authenticate header.
|
||||
IFS=',' read -ra PARAMS <<< "$wo_auth_call_resp_header"
|
||||
|
||||
for (( i = 0; i < 2; ++i )); do
|
||||
if [ $i == 0 ]; then
|
||||
__extract_auth_server ${PARAMS[0]}
|
||||
else
|
||||
__extract_resource_type ${PARAMS[1]}
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
############# Helper functions #############
|
||||
|
||||
#Removes Bearer authorization prefix to extract auth server url from 401 redirect of keyvault.
|
||||
__extract_auth_server() {
|
||||
AUTH_SERVER_URL=$(__remove_double_quotes $2)
|
||||
}
|
||||
|
||||
#Removes "resource" prefix to extract resource type from 401 redirect of keyvault.
|
||||
__extract_resource_type() {
|
||||
RESOURCE_TYPE=$(__remove_double_quotes $1)
|
||||
}
|
||||
|
||||
__remove_double_quotes() {
|
||||
local input=$1
|
||||
# Remove trailing and prefixed double quotes.
|
||||
local _value=${input#*'"'}
|
||||
_value=${_value%'"'}
|
||||
|
||||
#return the value
|
||||
echo $_value
|
||||
}
|
||||
|
||||
__parse_json() {
|
||||
_value=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w $2`;
|
||||
echo ${_value##*|};
|
||||
}
|
||||
|
||||
############# Main function #############
|
||||
|
||||
set_env_vars() {
|
||||
# parse through all variables (Every odd variable is env var name & even variables are secret key names in Key vault).
|
||||
while test ${#} -gt 0
|
||||
do
|
||||
_key=$1
|
||||
_value=$(_get_keyvault_secret $2)
|
||||
|
||||
# export in current shell
|
||||
export $_key=$_value
|
||||
|
||||
shift
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
main() {
|
||||
if [[ "$PCS_KEYVAULT_NAME" != "" ]] && [[ "$PCS_AAD_APPID" != "" ]] && [[ "$PCS_AAD_APPSECRET" != "" ]]; then
|
||||
set_env_vars $@
|
||||
fi
|
||||
}
|
||||
|
||||
main $@
|
|
@ -15,12 +15,9 @@ run_container() {
|
|||
# Depending on which settings and which dependencies are needed, edit the list of variables
|
||||
echo "Starting Auth ..."
|
||||
docker run -it -p 9001:9001 \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_AAD_ENDPOINT_URL \
|
||||
-e PCS_AAD_TENANT \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
-e PCS_ARM_ENDPOINT_URL \
|
||||
"$DOCKER_IMAGE:testing"
|
||||
}
|
||||
|
||||
|
|
|
@ -19,12 +19,9 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
|
|||
:: Start the application
|
||||
echo Starting Auth ...
|
||||
docker run -it -p 9001:9001 ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_AAD_ENDPOINT_URL ^
|
||||
-e PCS_AAD_TENANT ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
-e PCS_ARM_ENDPOINT_URL ^
|
||||
%DOCKER_IMAGE%:testing
|
||||
|
||||
:: - - - - - - - - - - - - - -
|
||||
|
|
|
@ -1,54 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# Before checking all the env vars, detect whether secrets, usually encrypted, are available or not.
|
||||
# Secrets are not available when building a pull request, so the script will not check for those.
|
||||
detect_secrets() {
|
||||
SECRETS_AVAILABLE="true"
|
||||
if [[ "$TRAVIS_PULL_REQUEST" != "" && "$TRAVIS_PULL_REQUEST" != "false" ]]; then
|
||||
SECRETS_AVAILABLE="false"
|
||||
echo "Warning: secrets and encrypted variables are not available when testing pull requests."
|
||||
fi
|
||||
}
|
||||
|
||||
detect_secrets
|
||||
|
||||
# if [[ -z "$SOMETHING_SECRET" && "$SECRETS_AVAILABLE" = "true" ]]; then
|
||||
# echo "Error: the SOMETHING_SECRET environment variable is not defined."
|
||||
# exit -1
|
||||
# fi
|
||||
|
||||
# if [[ -z "$SOMETHING_NOT_SECRET" ]]; then
|
||||
# echo "Error: the SOMETHING_NOT_SECRET environment variable is not defined."
|
||||
# exit -1
|
||||
# fi
|
||||
|
||||
if [[ -z "$PCS_AUTH_ISSUER" ]]; then
|
||||
echo "Error: the PCS_AUTH_ISSUER environment variable is not defined."
|
||||
exit -1
|
||||
if [[ -z "$PCS_KEYVAULT_NAME" ]]; then
|
||||
echo "Error: the PCS_KEYVAULT_NAME environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AUTH_AUDIENCE" ]]; then
|
||||
echo "Error: the PCS_AUTH_AUDIENCE environment variable is not defined."
|
||||
exit -1
|
||||
if [[ -z "$PCS_AAD_APPID" ]]; then
|
||||
echo "Error: the PCS_AAD_APPID environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_AAD_ENDPOINT_URL" ]]; then
|
||||
echo "Error: the PCS_AAD_ENDPOINT_URL environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_AAD_TENANT" ]]; then
|
||||
echo "Error: the PCS_AAD_TENANT environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_AAD_APPSECRET" ]]; then
|
||||
if [[ -z "$PCS_AAD_APPSECRET" ]]; then
|
||||
echo "Error: the PCS_AAD_APPSECRET environment variable is not defined."
|
||||
exit -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "PCS_ARM_ENDPOINT_URL" ]]; then
|
||||
echo "Error: the PCS_ARM_ENDPOINT_URL environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
|
@ -1,22 +1,14 @@
|
|||
:: Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
IF "%PCS_AUTH_ISSUER%" == "" (
|
||||
echo Error: the PCS_AUTH_ISSUER environment variable is not defined.
|
||||
IF "%PCS_KEYVAULT_NAME%" == "" (
|
||||
echo Error: the PCS_KEYVAULT_NAME environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AUTH_AUDIENCE%" == "" (
|
||||
echo Error: the PCS_AUTH_AUDIENCE environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AAD_ENDPOINT_URL%" == "" (
|
||||
echo Error: the PCS_AAD_ENDPOINT_URL environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AAD_TENANT%" == "" (
|
||||
echo Error: the PCS_AAD_TENANT environment variable is not defined.
|
||||
IF "%PCS_AAD_APPID%" == "" (
|
||||
echo Error: the PCS_AAD_APPID environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
|
@ -25,9 +17,4 @@ IF "%PCS_AAD_APPSECRET%" == "" (
|
|||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_ARM_ENDPOINT_URL%" == "" (
|
||||
echo Error: the PCS_ARM_ENDPOINT_URL environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
endlocal
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Usage: source ./scripts/env-vars-setup
|
||||
#
|
||||
# IMPORTANT NOTES:
|
||||
# * use "source" in front of the script path, so that variables are exported in your shell
|
||||
# * the variables are set only in the current shell, run this script every time, or automate
|
||||
# the setup using your `~/.bash_profile`.
|
||||
|
||||
# Prepare the environment variables used by the application.
|
||||
|
||||
# The OpenId tokens issuer URL, e.g. https://sts.windows.net/12000000-3400-5600-0000-780000000000/
|
||||
export PCS_AUTH_ISSUER="{enter the token issuer URL here}"
|
||||
|
||||
# The intended audience of the tokens, e.g. your Client Id
|
||||
export PCS_AUTH_AUDIENCE="{enter the tokens audience here}"
|
||||
|
||||
# Azure Active Directory endpoint url, e.g. https://login.microsoftonline.com/
|
||||
export PCS_AAD_ENDPOINT_URL="{enter the AAD endpoint URL here}"
|
||||
|
||||
# The tenant id of Azure Active Directory
|
||||
export PCS_AAD_TENANT="{enter the tenant id of AAD here}"
|
||||
|
||||
# The secret of intended application audience
|
||||
export PCS_AAD_APPSECRET="{enter the secret of AAD application here}"
|
||||
|
||||
# Azure Resource Manager endpoint url, e.g. https://management.azure.com/
|
||||
export PCS_ARM_ENDPOINT_URL="{enter the endpoint URL of Azure Resource Manager here}"
|
|
@ -1,19 +0,0 @@
|
|||
:: Prepare the environment variables used by the application.
|
||||
|
||||
:: The OpenId tokens issuer URL, e.g. https://sts.windows.net/12000000-3400-5600-0000-780000000000/
|
||||
SETX PCS_AUTH_ISSUER "{enter the token issuer URL here}"
|
||||
|
||||
:: The intended audience of the tokens, e.g. your Client Id
|
||||
SETX PCS_AUTH_AUDIENCE "{enter the tokens audience here}"
|
||||
|
||||
# Azure Active Directory endpoint url, e.g. https://login.microsoftonline.com/
|
||||
SETX PCS_AAD_ENDPOINT_URL "{enter the AAD endpoint URL here}"
|
||||
|
||||
# The tenant id of Azure Active Directory
|
||||
SETX PCS_AAD_TENANT "{enter the tenant id of AAD here}"
|
||||
|
||||
# The secret of intended application audience
|
||||
SETX PCS_AAD_APPSECRET "{enter the secret of AAD application here}"
|
||||
|
||||
# Azure Resource Manager endpoint url, e.g. https://management.azure.com/
|
||||
SETX PCS_ARM_ENDPOINT_URL "{enter the endpoint URL of Azure Resource Manager here}"
|
|
@ -58,12 +58,9 @@ run_in_sandbox() {
|
|||
# edit the list of variables.
|
||||
docker run -it \
|
||||
-p 9001:9001 \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_AAD_ENDPOINT_URL \
|
||||
-e PCS_AAD_TENANT \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
-e PCS_ARM_ENDPOINT_URL \
|
||||
-v "$PCS_CACHE/sandbox/.config:/root/.config" \
|
||||
-v "$PCS_CACHE/sandbox/.dotnet:/root/.dotnet" \
|
||||
-v "$PCS_CACHE/sandbox/.nuget:/root/.nuget" \
|
||||
|
|
|
@ -61,12 +61,9 @@ IF "%1"=="--in-sandbox" GOTO :RunInSandbox
|
|||
:: Start the sandbox and run the service
|
||||
docker run -it ^
|
||||
-p 9001:9001 ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_AAD_ENDPOINT_URL ^
|
||||
-e PCS_AAD_TENANT ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
-e PCS_ARM_ENDPOINT_URL ^
|
||||
-v %PCS_CACHE%\sandbox\.config:/root/.config ^
|
||||
-v %PCS_CACHE%\sandbox\.dotnet:/root/.dotnet ^
|
||||
-v %PCS_CACHE%\sandbox\.nuget:/root/.nuget ^
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Example usage (see "travis help" for more information):
|
||||
# travis help
|
||||
# travis login --pro
|
||||
# travis whoami --pro
|
||||
# travis accounts --pro
|
||||
# travis history
|
||||
# travis monitor --pro
|
||||
# travis settings
|
||||
# travis show
|
||||
# travis status
|
||||
# travis token --pro
|
||||
# travis whatsup --pro
|
||||
|
||||
set -e
|
||||
APP_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )/"
|
||||
cd $APP_HOME
|
||||
|
||||
mkdir -p .travis
|
||||
|
||||
docker run -it \
|
||||
-v $APP_HOME/.travis:/root/.travis \
|
||||
-v $APP_HOME:/opt/code \
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh $*
|
||||
|
||||
set +e
|
|
@ -1,28 +0,0 @@
|
|||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
:: Example usage (see "travis help" for more information:
|
||||
:: travis help
|
||||
:: travis login --pro
|
||||
:: travis whoami --pro
|
||||
:: travis accounts --pro
|
||||
:: travis history
|
||||
:: travis monitor --pro
|
||||
:: travis settings
|
||||
:: travis show
|
||||
:: travis status
|
||||
:: travis token --pro
|
||||
:: travis whatsup --pro
|
||||
|
||||
:: strlen("\scripts\") => 9
|
||||
SET APP_HOME=%~dp0
|
||||
SET APP_HOME=%APP_HOME:~0,-9%
|
||||
cd %APP_HOME%
|
||||
|
||||
mkdir .travis 2>NUL
|
||||
|
||||
docker run -it ^
|
||||
-v %APP_HOME%\.travis:/root/.travis ^
|
||||
-v %APP_HOME%:/opt/code ^
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh %*
|
||||
|
||||
endlocal
|
|
@ -23,28 +23,38 @@ namespace Microsoft.Azure.IoTSolutions.UIConfig.Services.Runtime
|
|||
private readonly IConfigurationRoot configuration;
|
||||
private readonly ILogger log;
|
||||
|
||||
// Key Vault
|
||||
private KeyVault keyVault;
|
||||
|
||||
// Constants
|
||||
private const string CLIENT_ID = "KeyVault:aadAppId";
|
||||
private const string CLIENT_SECRET = "KeyVault:aadAppSecret";
|
||||
private const string KEY_VAULT_NAME = "KeyVault:name";
|
||||
|
||||
public ConfigData(ILogger logger)
|
||||
{
|
||||
this.log = logger;
|
||||
|
||||
// More info about configuration at
|
||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration
|
||||
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true);
|
||||
this.configuration = configurationBuilder.Build();
|
||||
|
||||
// Set up Key Vault
|
||||
this.SetUpKeyVault();
|
||||
}
|
||||
|
||||
public string GetString(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
var value = this.GetSecrets(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool GetBool(string key, bool defaultValue = false)
|
||||
{
|
||||
var value = this.GetString(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
var value = this.GetSecrets(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
|
||||
var knownTrue = new HashSet<string> { "true", "t", "yes", "y", "1", "-1" };
|
||||
var knownFalse = new HashSet<string> { "false", "f", "no", "n", "0" };
|
||||
|
@ -59,7 +69,7 @@ namespace Microsoft.Azure.IoTSolutions.UIConfig.Services.Runtime
|
|||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(this.GetString(key, defaultValue.ToString()));
|
||||
return Convert.ToInt32(this.GetSecrets(key, defaultValue.ToString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -67,6 +77,49 @@ namespace Microsoft.Azure.IoTSolutions.UIConfig.Services.Runtime
|
|||
}
|
||||
}
|
||||
|
||||
private void SetUpKeyVault()
|
||||
{
|
||||
var clientId = this.GetEnvironmentVariable(CLIENT_ID, string.Empty);
|
||||
var clientSecret = this.GetEnvironmentVariable(CLIENT_SECRET, string.Empty);
|
||||
var keyVaultName = this.GetEnvironmentVariable(KEY_VAULT_NAME, string.Empty);
|
||||
|
||||
// Initailize key vault
|
||||
this.keyVault = new KeyVault(keyVaultName, clientId, clientSecret, this.log);
|
||||
}
|
||||
|
||||
private string GetSecrets(string key, string defaultValue = "")
|
||||
{
|
||||
string value = string.Empty;
|
||||
|
||||
value = this.GetLocalVariables(key, defaultValue);
|
||||
|
||||
// If secrets are not found locally, search in Key-Vault
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
log.Warn($"Value for secret {key} not found in local env. " +
|
||||
$" Trying to get the secret from KeyVault.", () => { });
|
||||
value = this.keyVault.GetSecret(key);
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
private string GetSecretsFromKeyVault(string key) {
|
||||
return this.keyVault.GetSecret(key);
|
||||
}
|
||||
|
||||
private string GetLocalVariables(string key, string defaultValue = "")
|
||||
{
|
||||
return this.configuration.GetValue(key, defaultValue);
|
||||
}
|
||||
|
||||
public string GetEnvironmentVariable(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void ReplaceEnvironmentVariables(ref string value, string defaultValue = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return;
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.IoTSolutions.UIConfig.Services.Diagnostics;
|
||||
using Microsoft.Azure.KeyVault;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.UIConfig.Services.Runtime
|
||||
{
|
||||
public class KeyVault
|
||||
{
|
||||
|
||||
// Key Vault details and access
|
||||
private readonly string name;
|
||||
private readonly string clientId;
|
||||
private readonly string clientSecret;
|
||||
private ILogger log;
|
||||
|
||||
// Key Vault Client
|
||||
private readonly KeyVaultClient keyVaultClient;
|
||||
|
||||
// Constants
|
||||
private const string KEY_VAULT_URI = "https://{0}.vault.azure.net/secrets/{1}";
|
||||
|
||||
public KeyVault(
|
||||
string name,
|
||||
string clientId,
|
||||
string clientSecret,
|
||||
ILogger logger)
|
||||
{
|
||||
this.name = name;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.log = logger;
|
||||
this.keyVaultClient = new KeyVaultClient(
|
||||
new KeyVaultClient.AuthenticationCallback(this.GetToken));
|
||||
}
|
||||
|
||||
public string GetSecret(string secretKey)
|
||||
{
|
||||
secretKey = secretKey.Split(':').Last();
|
||||
var uri = string.Format(KEY_VAULT_URI, this.name, secretKey);
|
||||
|
||||
try
|
||||
{
|
||||
return this.keyVaultClient.GetSecretAsync(uri).Result.Value;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.log.Error($"Secret {secretKey} not found in Key Vault.", () => { });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//the method that will be provided to the KeyVaultClient
|
||||
private async Task<string> GetToken(string authority, string resource, string scope)
|
||||
{
|
||||
var authContext = new AuthenticationContext(authority);
|
||||
ClientCredential clientCred = new ClientCredential(this.clientId, this.clientSecret);
|
||||
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
this.log.Debug($"Failed to obtain authentication token from key vault.", () => { });
|
||||
throw new System.InvalidOperationException("Failed to obtain the JWT token");
|
||||
}
|
||||
|
||||
return result.AccessToken;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="2.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.Azure.KeyVault" Version="2.0.6" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Data\device-simulation-template.json">
|
||||
|
|
|
@ -1,26 +1,23 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:9005/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"WebService": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:9005/v1/status",
|
||||
"environmentVariables": {
|
||||
"PCS_STORAGEADAPTER_WEBSERVICE_URL": "http://localhost:9022/v1",
|
||||
"PCS_TELEMETRY_WEBSERVICE_URL": "http://localhost:9004/v1",
|
||||
"PCS_DEVICESIMULATION_WEBSERVICE_URL": "http://localhost:9003/v1",
|
||||
"PCS_AZUREMAPS_KEY": "static",
|
||||
"PCS_AUTH_WEBSERVICE_URL": "http://localhost:9001/v1",
|
||||
"PCS_AUTH_REQUIRED": "false"
|
||||
},
|
||||
"applicationUrl": "http://localhost:9005/v1/status"
|
||||
}
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:9005/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"WebService": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:9005/v1/status",
|
||||
"environmentVariables": {
|
||||
"PCS_KEYVAULT_NAME": "$(PCS_KEYVAULT_NAME)",
|
||||
"PCS_AAD_APPID": "$(PCS_AAD_APPID)",
|
||||
"PCS_AAD_APPSECRET": "$(PCS_AAD_APPSECRET)"
|
||||
},
|
||||
"applicationUrl": "http://localhost:9005/v1/status"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,39 +22,39 @@ namespace Microsoft.Azure.IoTSolutions.UIConfig.WebService.Runtime
|
|||
public class Config : IConfig
|
||||
{
|
||||
private const string APPLICATION_KEY = "ConfigService:";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservice_port";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservicePort";
|
||||
private const string SOLUTION_TYPE_KEY = APPLICATION_KEY + "solutionType";
|
||||
private const string SEED_TEMPLATE_KEY = APPLICATION_KEY + "seedTemplate";
|
||||
private const string AZURE_MAPS_KEY = APPLICATION_KEY + "azuremaps_key";
|
||||
private const string AZURE_MAPS_KEY = APPLICATION_KEY + "azureMapsKey";
|
||||
|
||||
private const string STORAGE_ADAPTER_KEY = "StorageAdapterService:";
|
||||
private const string STORAGE_ADAPTER_URL_KEY = STORAGE_ADAPTER_KEY + "webservice_url";
|
||||
private const string EXTERNAL_DEPENDENCIES_KEY = "ExternalDependencies:";
|
||||
private const string STORAGE_ADAPTER_URL_KEY = EXTERNAL_DEPENDENCIES_KEY + "storageAdapterWebServiceUrl";
|
||||
private const string DEVICE_SIMULATION_URL_KEY = EXTERNAL_DEPENDENCIES_KEY + "deviceSimulationWebServiceUrl";
|
||||
private const string TELEMETRY_URL_KEY = EXTERNAL_DEPENDENCIES_KEY + "telemetryWebServiceUrl";
|
||||
|
||||
private const string DEVICE_SIMULATION_KEY = "DeviceSimulationService:";
|
||||
private const string DEVICE_SIMULATION_URL_KEY = DEVICE_SIMULATION_KEY + "webservice_url";
|
||||
private const string TELEMETRY_KEY = "TelemetryService:";
|
||||
private const string TELEMETRY_URL_KEY = TELEMETRY_KEY + "webservice_url";
|
||||
|
||||
private const string CLIENT_AUTH_KEY = APPLICATION_KEY + "ClientAuth:";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "cors_whitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "auth_type";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "auth_required";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "corsWhitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "authType";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "authRequired";
|
||||
|
||||
private const string JWT_KEY = APPLICATION_KEY + "ClientAuth:JWT:";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowed_algorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "issuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "audience";
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clock_skew_seconds";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowedAlgorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "authIssuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "aadAppId";
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clockSkewSeconds";
|
||||
|
||||
private const string USER_MANAGEMENT_KEY = "UserManagementService:";
|
||||
private const string USER_MANAGEMENT_URL_KEY = USER_MANAGEMENT_KEY + "webservice_url";
|
||||
private const string USER_MANAGEMENT_URL_KEY = USER_MANAGEMENT_KEY + "authWebServiceUrl";
|
||||
|
||||
private const string ACTIONS_KEY = APPLICATION_KEY + "Actions:";
|
||||
private const string OFFICE365_LOGIC_APP_URL_KEY = ACTIONS_KEY + "office365_logic_app_url";
|
||||
private const string RESOURCE_GROUP_KEY = ACTIONS_KEY + "resource_group";
|
||||
private const string SUBSCRIPTION_ID_KEY = ACTIONS_KEY + "subscription_id";
|
||||
private const string MANAGEMENT_API_VERSION_KEY = ACTIONS_KEY + "management_api_version";
|
||||
private const string ARM_ENDPOINT_URL_KEY = ACTIONS_KEY + "arm_endpoint_url";
|
||||
private const string OFFICE365_LOGIC_APP_URL_KEY = ACTIONS_KEY + "office365ConnectionUrl";
|
||||
private const string RESOURCE_GROUP_KEY = ACTIONS_KEY + "solutionName";
|
||||
private const string SUBSCRIPTION_ID_KEY = ACTIONS_KEY + "subscriptionId";
|
||||
private const string MANAGEMENT_API_VERSION_KEY = ACTIONS_KEY + "managementApiVersion";
|
||||
private const string ARM_ENDPOINT_URL_KEY = ACTIONS_KEY + "armEndpointUrl";
|
||||
|
||||
public int Port { get; }
|
||||
public IServicesConfig ServicesConfig { get; }
|
||||
|
|
|
@ -1,56 +1,46 @@
|
|||
[ConfigService]
|
||||
webservice_port = 9005
|
||||
solutionType = "${?PCS_SOLUTION_TYPE}"
|
||||
seedTemplate = "${?PCS_SEED_TEMPLATE}"
|
||||
azuremaps_key = "${PCS_AZUREMAPS_KEY}"
|
||||
|
||||
|
||||
[StorageAdapterService]
|
||||
webservice_url = "${PCS_STORAGEADAPTER_WEBSERVICE_URL}"
|
||||
|
||||
|
||||
[DeviceSimulationService]
|
||||
webservice_url = "${PCS_DEVICESIMULATION_WEBSERVICE_URL}"
|
||||
|
||||
|
||||
[TelemetryService]
|
||||
webservice_url = "${PCS_TELEMETRY_WEBSERVICE_URL}"
|
||||
|
||||
|
||||
[UserManagementService]
|
||||
webservice_url = "${PCS_AUTH_WEBSERVICE_URL}"
|
||||
webservicePort = 9005
|
||||
solutionType = ""
|
||||
seedTemplate = ""
|
||||
azureMapsKey = ""
|
||||
|
||||
[ExternalDependencies]
|
||||
;; Urls to external services
|
||||
storageAdapterWebServiceUrl = ""
|
||||
deviceSimulationWebServiceUrl = ""
|
||||
telemetryWebServiceUrl = ""
|
||||
authWebServiceUrl = ""
|
||||
|
||||
[ConfigService:Actions]
|
||||
;; Url for the Office365 Logic App Connector in the Azure portal
|
||||
office365_logic_app_url = "${PCS_OFFICE365_CONNECTION_URL}"
|
||||
office365ConnectionUrl = ""
|
||||
;; Resource group name, arm endpoint, and Subscription ID for the
|
||||
;; Office365 Logic App Connector API call.
|
||||
resource_group = "${PCS_SOLUTION_NAME}"
|
||||
subscription_id = "${PCS_SUBSCRIPTION_ID}"
|
||||
arm_endpoint_url = "${PCS_ARM_ENDPOINT_URL}"
|
||||
solutionName = ""
|
||||
subscriptionId = ""
|
||||
armEndpointUrl = ""
|
||||
;; api version for the azure management apis
|
||||
management_api_version = "2016-06-01"
|
||||
managementApiVersion = "2016-06-01"
|
||||
|
||||
|
||||
[ConfigService:ClientAuth]
|
||||
;; Current auth type, only "JWT" is currently supported.
|
||||
auth_type="JWT"
|
||||
authType="JWT"
|
||||
;; This can be changed to false, for example during development,
|
||||
;; to allow invalid/missing authorizations.
|
||||
;; Default: true
|
||||
auth_required="${?PCS_AUTH_REQUIRED}"
|
||||
authRequired=""
|
||||
;; Can be used when running services on multiple hostnames and/or ports
|
||||
;; e.g. "{ 'origins': ['*'], 'methods': ['*'], 'headers': ['*'] }" to allow everything.
|
||||
;; Comment it or leave it empty to disable CORS.
|
||||
;; Default: empty
|
||||
cors_whitelist = "${?PCS_CORS_WHITELIST}"
|
||||
corsWhitelist = ""
|
||||
|
||||
|
||||
[ConfigService:ClientAuth:JWT]
|
||||
; Trusted algorithms
|
||||
; Default: RS256, RS384, RS512
|
||||
allowed_algorithms="RS256"
|
||||
allowedAlgorithms="RS256"
|
||||
; Identifies the security token service (STS) that constructs and returns the token.
|
||||
; In the tokens that Azure AD returns, the issuer is sts.windows.net. The GUID in
|
||||
; the Issuer claim value is the tenant ID of the Azure AD directory. The tenant ID
|
||||
|
@ -59,15 +49,19 @@ allowed_algorithms="RS256"
|
|||
; When using Azure Active Directory, the format of the Issuer is:
|
||||
; https://sts.windows.net/<tenant Id>/
|
||||
; example: issuer="https://sts.windows.net/fa01ade2-2365-4dd1-a084-a6ef027090fc/"
|
||||
issuer="${?PCS_AUTH_ISSUER}"
|
||||
authIssuer=""
|
||||
; Used to verify that tokens are issued to be given to this service
|
||||
; Also referenced as "Application Id" and "Resource Id"
|
||||
; example: audience="2814e709-6a0e-4861-9594-d3b6e2b81331"
|
||||
audience="${?PCS_AUTH_AUDIENCE}"
|
||||
aadTenantId=""
|
||||
; When validating the token expiration, allows some clock skew
|
||||
; Default: 2 minutes
|
||||
clock_skew_seconds = 300
|
||||
clockSkewSeconds = 300
|
||||
|
||||
[KeyVault]
|
||||
aadAppId = ${PCS_AAD_APPID}
|
||||
aadAppSecret = ${PCS_AAD_APPSECRET}
|
||||
name = ${PCS_KEYVAULT_NAME}
|
||||
|
||||
; For more information about ASP.NET logging see
|
||||
; https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging
|
||||
|
@ -75,7 +69,8 @@ clock_skew_seconds = 300
|
|||
; internal logs generated by ASP.NET
|
||||
; ASP.NET log levels: Trace, Debug, Information, Warning, Error, Critical
|
||||
[Logging]
|
||||
IncludeScopes = true
|
||||
includeScopes = true
|
||||
|
||||
LogLevel:Default = "Warning"
|
||||
LogLevel:System = "Warning"
|
||||
LogLevel:Microsoft = "Warning"
|
||||
|
|
|
@ -13,22 +13,9 @@ run_container() {
|
|||
|
||||
echo "Starting Config service ..."
|
||||
docker run -it -p 9005:9005 \
|
||||
-e PCS_AUTH_WEBSERVICE_URL \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
|
||||
-e PCS_DEVICESIMULATION_WEBSERVICE_URL \
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL \
|
||||
-e PCS_SOLUTION_TYPE \
|
||||
-e PCS_AZUREMAPS_KEY \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_AUTH_REQUIRED \
|
||||
-e PCS_CORS_WHITELIST \
|
||||
-e PCS_APPLICATION_SECRET \
|
||||
-e PCS_OFFICE365_CONNECTION_URL \
|
||||
-e PCS_SOLUTION_NAME \
|
||||
-e PCS_SUBSCRIPTION_ID \
|
||||
-e PCS_ARM_ENDPOINT_URL \
|
||||
-e PCS_SEED_TEMPLATE \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
"$DOCKER_IMAGE:testing"
|
||||
}
|
||||
|
||||
|
|
|
@ -19,22 +19,9 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
|
|||
:: Start the application
|
||||
echo Starting Config web service ...
|
||||
docker run -it -p 9005:9005 ^
|
||||
-e PCS_AUTH_WEBSERVICE_URL ^
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
|
||||
-e PCS_DEVICESIMULATION_WEBSERVICE_URL ^
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL ^
|
||||
-e PCS_SOLUTION_TYPE ^
|
||||
-e PCS_AZUREMAPS_KEY ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_AUTH_REQUIRED ^
|
||||
-e PCS_CORS_WHITELIST ^
|
||||
-e PCS_APPLICATION_SECRET ^
|
||||
-e PCS_OFFICE365_CONNECTION_URL ^
|
||||
-e PCS_SOLUTION_NAME ^
|
||||
-e PCS_SUBSCRIPTION_ID ^
|
||||
-e PCS_ARM_ENDPOINT_URL ^
|
||||
-e PCS_SEED_TEMPLATE ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
%DOCKER_IMAGE%:testing
|
||||
|
||||
:: - - - - - - - - - - - - - -
|
||||
|
|
|
@ -1,55 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# Before checking all the env vars, detect whether secrets, usually encrypted, are available or not.
|
||||
# Secrets are not available when building a pull request, so the script will not check for those.
|
||||
detect_secrets() {
|
||||
SECRETS_AVAILABLE="true"
|
||||
if [[ "$TRAVIS_PULL_REQUEST" != "" && "$TRAVIS_PULL_REQUEST" != "false" ]]; then
|
||||
SECRETS_AVAILABLE="false"
|
||||
echo "Warning: secrets and encrypted variables are not available when testing pull requests."
|
||||
fi
|
||||
}
|
||||
|
||||
detect_secrets
|
||||
|
||||
if [[ -z "$PCS_STORAGEADAPTER_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_STORAGEADAPTER_WEBSERVICE_URL environment variable is not defined."
|
||||
exit -1
|
||||
if [[ -z "$PCS_KEYVAULT_NAME" ]]; then
|
||||
echo "Error: the PCS_KEYVAULT_NAME environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_DEVICESIMULATION_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_DEVICESIMULATION_WEBSERVICE_URL environment variable is not defined."
|
||||
exit -1
|
||||
if [[ -z "$PCS_AAD_APPID" ]]; then
|
||||
echo "Error: the PCS_AAD_APPID environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_TELEMETRY_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_TELEMETRY_WEBSERVICE_URL environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AZUREMAPS_KEY" && "$SECRETS_AVAILABLE" = "true" ]]; then
|
||||
echo "Error: the PCS_AZUREMAPS_KEY environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AUTH_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_AUTH_WEBSERVICE_URL environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Optional environment variables
|
||||
if [[ -z "$PCS_OFFICE365_CONNECTION_URL" ]]; then
|
||||
echo "Warning: the PCS_OFFICE365_CONNECTION_URL environment variable is not defined."
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_SOLUTION_NAME" ]]; then
|
||||
echo "Warning: the PCS_SOLUTION_NAME environment variable is not defined."
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_SUBSCRIPTION_ID" ]]; then
|
||||
echo "Warning: the PCS_SUBSCRIPTION_ID environment variable is not defined."
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_ARM_ENDPOINT_URL" ]]; then
|
||||
echo "Warning: the PCS_ARM_ENDPOINT_URL environment variable is not defined."
|
||||
if [[ -z "$PCS_AAD_APPSECRET" ]]; then
|
||||
echo "Error: the PCS_AAD_APPSECRET environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
@ -1,45 +1,20 @@
|
|||
:: Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
IF "%PCS_STORAGEADAPTER_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_STORAGEADAPTER_WEBSERVICE_URL environment variable is not defined.
|
||||
IF "%PCS_KEYVAULT_NAME%" == "" (
|
||||
echo Error: the PCS_KEYVAULT_NAME environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_DEVICESIMULATION_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_DEVICESIMULATION_WEBSERVICE_URL environment variable is not defined.
|
||||
IF "%PCS_AAD_APPID%" == "" (
|
||||
echo Error: the PCS_AAD_APPID environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_TELEMETRY_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_TELEMETRY_WEBSERVICE_URL environment variable is not defined.
|
||||
IF "%PCS_AAD_APPSECRET%" == "" (
|
||||
echo Error: the PCS_AAD_APPSECRET environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AZUREMAPS_KEY%" == "" (
|
||||
echo Error: the PCS_AZUREMAPS_KEY environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AUTH_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_AUTH_WEBSERVICE_URL environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
:: Optional environment variables
|
||||
IF "%PCS_OFFICE365_CONNECTION_URL%" == "" (
|
||||
echo Warning: the PCS_OFFICE365_CONNECTION_URL environment variable is not defined.
|
||||
)
|
||||
|
||||
IF "%PCS_SOLUTION_NAME%" == "" (
|
||||
echo Warning: the $PCS_SOLUTION_NAME environment variable is not defined.
|
||||
)
|
||||
|
||||
IF "%PCS_SUBSCRIPTION_ID%" == "" (
|
||||
echo Warning: the PCS_SUBSCRIPTION_ID environment variable is not defined.
|
||||
)
|
||||
|
||||
IF "%PCS_ARM_ENDPOINT_URL%" == "" (
|
||||
echo Warning: the PCS_ARM_ENDPOINT_URL environment variable is not defined.
|
||||
)
|
||||
|
||||
endlocal
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Usage: source ./scripts/env-vars-setup
|
||||
#
|
||||
# IMPORTANT NOTES:
|
||||
# * use "source" in front of the script path, so that variables are exported in your shell
|
||||
# * the variables are set only in the current shell, run this script every time, or automate
|
||||
# the setup using your `~/.bash_profile`.
|
||||
|
||||
# Prepare the environment variables used by the application
|
||||
|
||||
# The URL where Storage Adapter web service is listening
|
||||
export PCS_STORAGEADAPTER_WEBSERVICE_URL="http://127.0.0.1:9022/v1"
|
||||
|
||||
# The URL where Telemetry web service is listening
|
||||
export PCS_TELEMETRY_WEBSERVICE_URL="http://127.0.0.1:9004/v1"
|
||||
|
||||
# The URL where Device Simulation web service is listening
|
||||
export PCS_DEVICESIMULATION_WEBSERVICE_URL="http://127.0.0.1:9003/v1"
|
||||
|
||||
# The Azure Maps Api key
|
||||
export PCS_AZUREMAPS_KEY="static"
|
||||
|
||||
# The URL where Authentication web service is listening
|
||||
export PCS_AUTH_WEBSERVICE_URL="http://127.0.0.1:9001/v1"
|
|
@ -1,16 +0,0 @@
|
|||
:: Prepare the environment variables used by the application
|
||||
|
||||
:: Endpoint to reach the storage adapter
|
||||
SETX PCS_STORAGEADAPTER_WEBSERVICE_URL "http://localhost:9022/v1"
|
||||
|
||||
:: Endpoint to reach the telemetry
|
||||
SETX PCS_TELEMETRY_WEBSERVICE_URL "http://localhost:9004/v1"
|
||||
|
||||
:: Endpoint to reach the device simlation
|
||||
SETX PCS_DEVICESIMULATION_WEBSERVICE_URL "http://localhost:9003/v1"
|
||||
|
||||
:: Azure Maps API Key
|
||||
SETX PCS_AZUREMAPS_KEY "static"
|
||||
|
||||
:: Endpoint to reach the authentication service
|
||||
SETX PCS_AUTH_WEBSERVICE_URL "http://localhost:9001/v1"
|
|
@ -47,14 +47,9 @@ run_in_sandbox() {
|
|||
# edit the list of variables.
|
||||
docker run -it \
|
||||
-p 9005:9005 \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
|
||||
-e PCS_DEVICESIMULATION_WEBSERVICE_URL \
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL \
|
||||
-e PCS_AUTH_WEBSERVICE_URL \
|
||||
-e PCS_OFFICE365_CONNECTION_URL \
|
||||
-e PCS_SOLUTION_NAME \
|
||||
-e PCS_SUBSCRIPTION_ID \
|
||||
-e PCS_ARM_ENDPOINT_URL \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
-v "$PCS_CACHE/sandbox/.config:/root/.config" \
|
||||
-v "$PCS_CACHE/sandbox/.dotnet:/root/.dotnet" \
|
||||
-v "$PCS_CACHE/sandbox/.nuget:/root/.nuget" \
|
||||
|
|
|
@ -58,16 +58,11 @@ IF "%1"=="--in-sandbox" GOTO :RunInSandbox
|
|||
IF %ERRORLEVEL% NEQ 0 GOTO FAIL
|
||||
|
||||
:: Start the sandbox and run the application
|
||||
docker run -it ^
|
||||
docker run --detach ^
|
||||
-p 9005:9005 ^
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
|
||||
-e PCS_DEVICESIMULATION_WEBSERVICE_URL ^
|
||||
-e PCS_TELEMETRY_WEBSERVICE_URL ^
|
||||
-e PCS_AUTH_WEBSERVICE_URL ^
|
||||
-e PCS_OFFICE365_CONNECTION_URL ^
|
||||
-e PCS_SOLUTION_NAME ^
|
||||
-e PCS_SUBSCRIPTION_ID ^
|
||||
-e PCS_ARM_ENDPOINT_URL ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
-v %PCS_CACHE%\sandbox\.config:/root/.config ^
|
||||
-v %PCS_CACHE%\sandbox\.dotnet:/root/.dotnet ^
|
||||
-v %PCS_CACHE%\sandbox\.nuget:/root/.nuget ^
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
#!/usr/bin/env bash -e
|
||||
|
||||
# Example usage (see "travis help" for more information):
|
||||
# travis help
|
||||
# travis login --pro
|
||||
# travis whoami --pro
|
||||
# travis accounts --pro
|
||||
# travis history
|
||||
# travis monitor --pro
|
||||
# travis settings
|
||||
# travis show
|
||||
# travis status
|
||||
# travis token --pro
|
||||
# travis whatsup --pro
|
||||
|
||||
APP_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )/"
|
||||
cd $APP_HOME
|
||||
|
||||
mkdir -p .travis
|
||||
|
||||
docker run -it \
|
||||
-v $APP_HOME/.travis:/root/.travis \
|
||||
-v $APP_HOME:/opt/code \
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh $*
|
||||
|
||||
set +e
|
|
@ -1,28 +0,0 @@
|
|||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
:: Example usage (see "travis help" for more information:
|
||||
:: travis help
|
||||
:: travis login --pro
|
||||
:: travis whoami --pro
|
||||
:: travis accounts --pro
|
||||
:: travis history
|
||||
:: travis monitor --pro
|
||||
:: travis settings
|
||||
:: travis show
|
||||
:: travis status
|
||||
:: travis token --pro
|
||||
:: travis whatsup --pro
|
||||
|
||||
:: strlen("\scripts\") => 9
|
||||
SET APP_HOME=%~dp0
|
||||
SET APP_HOME=%APP_HOME:~0,-9%
|
||||
cd %APP_HOME%
|
||||
|
||||
mkdir .travis 2>NUL
|
||||
|
||||
docker run -it ^
|
||||
-v %APP_HOME%\.travis:/root/.travis ^
|
||||
-v %APP_HOME%:/opt/code ^
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh %*
|
||||
|
||||
endlocal
|
|
@ -3,4 +3,9 @@
|
|||
|
||||
cd /app/
|
||||
|
||||
echo "Setting environment variables."
|
||||
# Running in current shell
|
||||
. set_env.sh PCS_IOTHUB_CONNSTRING iotHubConnectionString PCS_STORAGEADAPTER_WEBSERVICE_URL storageAdapterWebServiceUrl
|
||||
|
||||
echo "Starting service."
|
||||
cd webservice && dotnet Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.dll
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
AUTH_SERVER_URL=""
|
||||
RESOURCE_TYPE=""
|
||||
AUTH_TOKEN=""
|
||||
|
||||
# Acquires auth token for authroizating against key vault.
|
||||
_acquire_token() {
|
||||
__set_keyvault_auth_server
|
||||
|
||||
local _temp=$(curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=$PCS_AAD_APPID&resource=https%3A%2F%2Fvault.azure.net&client_secret=$PCS_AAD_APPSECRET&grant_type=client_credentials" $AUTH_SERVER_URL/oauth2/token)
|
||||
AUTH_TOKEN=$(__parse_json $_temp "access_token")
|
||||
}
|
||||
|
||||
# Fetch key vault secret.
|
||||
_get_keyvault_secret() {
|
||||
|
||||
# Get a new token each time you access key vault.
|
||||
_acquire_token
|
||||
|
||||
_keyvault_secret_bundle=$(curl -H "Authorization: Bearer $AUTH_TOKEN" -L https://$PCS_KEYVAULT_NAME.vault.azure.net/secrets/$1/?api-version=7.0)
|
||||
_keyvault_secret_bundle="'$_keyvault_secret_bundle'"
|
||||
|
||||
# return the secret value.
|
||||
echo $(__parse_json $_keyvault_secret_bundle "value")
|
||||
}
|
||||
|
||||
# Gets keyvault auth server by examining response headers of unauthenticated request to key vault.
|
||||
# The 401 redirect contains WWW-Authenticate header which has KV auth server and resource type.
|
||||
__set_keyvault_auth_server() {
|
||||
|
||||
# Bare (unauthenticated) request to get secret.
|
||||
key_vault_wo_auth_call=$(curl -i -L "https://$PCS_KEYVAULT_NAME.vault.azure.net/secrets/authEnabled/?api-version=7.0" | grep -Fi WWW-Authenticate)
|
||||
|
||||
wo_auth_call_resp_header=${key_vault_wo_auth_call#*:}
|
||||
|
||||
# Extract auth server (url) & resource from WWW-Authenticate header.
|
||||
IFS=',' read -ra PARAMS <<< "$wo_auth_call_resp_header"
|
||||
|
||||
for (( i = 0; i < 2; ++i )); do
|
||||
if [ $i == 0 ]; then
|
||||
__extract_auth_server ${PARAMS[0]}
|
||||
else
|
||||
__extract_resource_type ${PARAMS[1]}
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
############# Helper functions #############
|
||||
|
||||
#Removes Bearer authorization prefix to extract auth server url from 401 redirect of keyvault.
|
||||
__extract_auth_server() {
|
||||
AUTH_SERVER_URL=$(__extract_value_from_double_quotes $2)
|
||||
}
|
||||
|
||||
#Removes "resource" prefix to extract resource type from 401 redirect of keyvault.
|
||||
__extract_resource_type() {
|
||||
RESOURCE_TYPE=$(__extract_value_from_double_quotes $1)
|
||||
}
|
||||
|
||||
__extract_value_from_double_quotes() {
|
||||
local string=$1
|
||||
# Remove trailing and prefixed double quotes.
|
||||
local _temp=${string#*'"'}
|
||||
_temp=${_temp%'"'}
|
||||
|
||||
#return the value
|
||||
echo $_temp
|
||||
}
|
||||
|
||||
__parse_json() {
|
||||
_temp=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w $2`;
|
||||
echo ${_temp##*|};
|
||||
}
|
||||
|
||||
############# Main function #############
|
||||
|
||||
set_env_vars() {
|
||||
# parse through all variables (Every odd variable is env var name & even variables are secret key names in Key vault).
|
||||
while test ${#} -gt 0
|
||||
do
|
||||
_key=$1
|
||||
_value=$(_get_keyvault_secret $2)
|
||||
|
||||
# export in current shell
|
||||
export $_key=$_value
|
||||
|
||||
shift
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
main() {
|
||||
if [[ "$PCS_KEYVAULT_NAME" != "" ]] && [[ "$PCS_AAD_APPID" != "" ]] && [[ "$PCS_AAD_APPSECRET" != "" ]]; then
|
||||
set_env_vars $@
|
||||
fi
|
||||
}
|
||||
|
||||
main $@
|
|
@ -16,10 +16,10 @@ run_container() {
|
|||
|
||||
echo "Starting Device Simulation ..."
|
||||
docker run --detach -p 9003:9003 \
|
||||
-e PCS_IOTHUB_CONNSTRING \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL="http://host.docker.internal:9022/v1" \
|
||||
-e PCS_SUBSCRIPTION_ID \
|
||||
"$DOCKER_IMAGE:DS-1.0.3"
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
"$DOCKER_IMAGE:DS-1.0.5"
|
||||
}
|
||||
|
||||
run_container
|
||||
|
|
|
@ -20,11 +20,11 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
|
|||
|
||||
:: Start the application
|
||||
echo Starting Device Simulation ...
|
||||
docker run -it -p 9003:9003 ^
|
||||
-e PCS_IOTHUB_CONNSTRING ^
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL="http://host.docker.internal:9022/v1" ^
|
||||
-e PCS_SUBSCRIPTION_ID ^
|
||||
%DOCKER_IMAGE%:testing
|
||||
docker run --detach -p 9003:9003 ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
%DOCKER_IMAGE%:DS-1.0.5
|
||||
|
||||
:: - - - - - - - - - - - - - -
|
||||
goto :END
|
||||
|
|
|
@ -1,24 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# Before checking all the env vars, detect whether secrets, usually encrypted, are available or not.
|
||||
# Secrets are not available when building a pull request, so the script will not check for those.
|
||||
detect_secrets() {
|
||||
SECRETS_AVAILABLE="true"
|
||||
if [[ "$TRAVIS_PULL_REQUEST" != "" && "$TRAVIS_PULL_REQUEST" != "false" ]]; then
|
||||
SECRETS_AVAILABLE="false"
|
||||
echo "Warning: secrets and encrypted variables are not available when testing pull requests."
|
||||
fi
|
||||
}
|
||||
|
||||
detect_secrets
|
||||
|
||||
if [[ -z "$PCS_IOTHUB_CONNSTRING" && "$SECRETS_AVAILABLE" = "true" ]]; then
|
||||
echo "Error: the PCS_IOTHUB_CONNSTRING environment variable is not defined."
|
||||
if [[ -z "$PCS_KEYVAULT_NAME" ]]; then
|
||||
echo "Error: the PCS_KEYVAULT_NAME environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_STORAGEADAPTER_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_STORAGEADAPTER_WEBSERVICE_URL environment variable is not defined."
|
||||
if [[ -z "$PCS_AAD_APPID" ]]; then
|
||||
echo "Error: the PCS_AAD_APPID environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AAD_APPSECRET" ]]; then
|
||||
echo "Error: the PCS_AAD_APPSECRET environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
@ -2,13 +2,18 @@
|
|||
|
||||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
IF "%PCS_IOTHUB_CONNSTRING%" == "" (
|
||||
echo Error: the PCS_IOTHUB_CONNSTRING environment variable is not defined.
|
||||
IF "%PCS_KEYVAULT_NAME%" == "" (
|
||||
echo Error: the PCS_KEYVAULT_NAME environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_STORAGEADAPTER_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_STORAGEADAPTER_WEBSERVICE_URL environment variable is not defined.
|
||||
IF "%PCS_AAD_APPID%" == "" (
|
||||
echo Error: the PCS_AAD_APPID environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AAD_APPSECRET%" == "" (
|
||||
echo Error: the PCS_AAD_APPSECRET environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# Prepare the environment variables used by the application.
|
||||
#
|
||||
# For more information about finding IoT Hub settings, more information here:
|
||||
#
|
||||
# * https://docs.microsoft.com/azure/iot-hub/iot-hub-create-through-portal#endpoints
|
||||
# * https://docs.microsoft.com/azure/iot-hub/iot-hub-csharp-csharp-getstarted
|
||||
#
|
||||
|
||||
# Azure IoT Hub Connection string
|
||||
export PCS_IOTHUB_CONNSTRING="your Azure IoT Hub connection string"
|
||||
|
||||
# Endpoint to reach the storage adapter
|
||||
export PCS_STORAGEADAPTER_WEBSERVICE_URL="http://127.0.0.1:9022/v1"
|
|
@ -1,15 +0,0 @@
|
|||
:: Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
:: Prepare the environment variables used by the application.
|
||||
::
|
||||
:: For more information about finding IoT Hub settings, more information here:
|
||||
::
|
||||
:: * https://docs.microsoft.com/azure/iot-hub/iot-hub-create-through-portal#endpoints
|
||||
:: * https://docs.microsoft.com/azure/iot-hub/iot-hub-csharp-csharp-getstarted
|
||||
::
|
||||
|
||||
:: Azure IoT Hub Connection string
|
||||
SETX PCS_IOTHUB_CONNSTRING "your Azure IoT Hub connection string"
|
||||
|
||||
:: Endpoint to reach the storage adapter
|
||||
SETX PCS_STORAGEADAPTER_WEBSERVICE_URL "http://127.0.0.1:9022/v1"
|
|
@ -23,28 +23,38 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Runtime
|
|||
private readonly IConfigurationRoot configuration;
|
||||
private readonly ILogger log;
|
||||
|
||||
// Key Vault
|
||||
private KeyVault keyVault;
|
||||
|
||||
// Constants
|
||||
private const string CLIENT_ID = "KeyVault:aadAppId";
|
||||
private const string CLIENT_SECRET = "KeyVault:aadAppSecret";
|
||||
private const string KEY_VAULT_NAME = "KeyVault:name";
|
||||
|
||||
public ConfigData(ILogger logger)
|
||||
{
|
||||
this.log = logger;
|
||||
|
||||
// More info about configuration at
|
||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration
|
||||
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true);
|
||||
this.configuration = configurationBuilder.Build();
|
||||
|
||||
// Set up Key Vault
|
||||
this.SetUpKeyVault();
|
||||
}
|
||||
|
||||
public string GetString(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
var value = this.GetSecrets(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool GetBool(string key, bool defaultValue = false)
|
||||
{
|
||||
var value = this.GetString(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
var value = this.GetSecrets(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
|
||||
var knownTrue = new HashSet<string> { "true", "t", "yes", "y", "1", "-1" };
|
||||
var knownFalse = new HashSet<string> { "false", "f", "no", "n", "0" };
|
||||
|
@ -59,7 +69,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Runtime
|
|||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(this.GetString(key, defaultValue.ToString()));
|
||||
return Convert.ToInt32(this.GetSecrets(key, defaultValue.ToString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -67,6 +77,49 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Runtime
|
|||
}
|
||||
}
|
||||
|
||||
private void SetUpKeyVault()
|
||||
{
|
||||
var clientId = this.GetEnvironmentVariable(CLIENT_ID, string.Empty);
|
||||
var clientSecret = this.GetEnvironmentVariable(CLIENT_SECRET, string.Empty);
|
||||
var keyVaultName = this.GetEnvironmentVariable(KEY_VAULT_NAME, string.Empty);
|
||||
|
||||
// Initailize key vault
|
||||
this.keyVault = new KeyVault(keyVaultName, clientId, clientSecret, this.log);
|
||||
}
|
||||
|
||||
private string GetSecrets(string key, string defaultValue = "")
|
||||
{
|
||||
string value = string.Empty;
|
||||
|
||||
value = this.GetLocalVariable(key, defaultValue);
|
||||
|
||||
// If secrets are not found locally, search in Key-Vault
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
log.Warn($"Value for secret {key} not found in local env. " +
|
||||
$" Trying to get the secret from KeyVault.", () => { });
|
||||
value = this.keyVault.GetSecret(key);
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
private string GetSecretsFromKeyVault(string key) {
|
||||
return this.keyVault.GetSecret(key);
|
||||
}
|
||||
|
||||
private string GetLocalVariable(string key, string defaultValue = "")
|
||||
{
|
||||
return this.configuration.GetValue(key, defaultValue);
|
||||
}
|
||||
|
||||
public string GetEnvironmentVariable(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void ReplaceEnvironmentVariables(ref string value, string defaultValue = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return;
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
using Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Diagnostics;
|
||||
using Microsoft.Azure.KeyVault;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.Services.Runtime
|
||||
{
|
||||
public class KeyVault
|
||||
{
|
||||
|
||||
// Key Vault details and access
|
||||
private readonly string name;
|
||||
private readonly string clientId;
|
||||
private readonly string clientSecret;
|
||||
private ILogger log;
|
||||
|
||||
// Key Vault Client
|
||||
private readonly KeyVaultClient keyVaultClient;
|
||||
|
||||
// Constants
|
||||
private const string KEY_VAULT_URI = "https://{0}.vault.azure.net/secrets/{1}";
|
||||
|
||||
public KeyVault(
|
||||
string name,
|
||||
string clientId,
|
||||
string clientSecret,
|
||||
ILogger logger)
|
||||
{
|
||||
this.name = name;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.log = logger;
|
||||
this.keyVaultClient = new KeyVaultClient(
|
||||
new KeyVaultClient.AuthenticationCallback(this.GetToken));
|
||||
}
|
||||
|
||||
public string GetSecret(string secretKey)
|
||||
{
|
||||
secretKey = secretKey.Split(':').Last();
|
||||
var uri = string.Format(KEY_VAULT_URI, this.name, secretKey);
|
||||
|
||||
try
|
||||
{
|
||||
return this.keyVaultClient.GetSecretAsync(uri).Result.Value;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
this.log.Error($"Secret {secretKey} not found in Key Vault.", () => { });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//the method that will be provided to the KeyVaultClient
|
||||
private async Task<string> GetToken(string authority, string resource, string scope)
|
||||
{
|
||||
var authContext = new AuthenticationContext(authority);
|
||||
ClientCredential clientCred = new ClientCredential(this.clientId, this.clientSecret);
|
||||
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
this.log.Debug($"Failed to obtain authentication token from key vault.", () => { });
|
||||
throw new System.InvalidOperationException("Failed to obtain the JWT token");
|
||||
}
|
||||
|
||||
return result.AccessToken;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="3.19.8" />
|
||||
<PackageReference Include="Microsoft.Azure.KeyVault" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Data\Rules\default.json">
|
||||
|
|
|
@ -13,21 +13,9 @@
|
|||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:9004/v1/status",
|
||||
"environmentVariables": {
|
||||
"PCS_TELEMETRY_DOCUMENTDB_CONNSTRING": "$(PCS_TELEMETRY_DOCUMENTDB_CONNSTRING)",
|
||||
"PCS_TELEMETRY_STORAGE_TYPE": "$(PCS_TELEMETRY_STORAGE_TYPE)",
|
||||
"PCS_STORAGEADAPTER_WEBSERVICE_URL": "http://localhost:9022/v1",
|
||||
"PCS_AUTH_WEBSERVICE_URL": "http://localhost:9001/v1",
|
||||
"PCS_TSI_FQDN": "$(PCS_TSI_FQDN)",
|
||||
"PCS_KEYVAULT_NAME": "$(PCS_KEYVAULT_NAME)",
|
||||
"PCS_AAD_APPID": "$(PCS_AAD_APPID)",
|
||||
"PCS_AAD_APPSECRET": "$(PCS_AAD_APPSECRET)",
|
||||
"PCS_AAD_TENANT": "$(PCS_AAD_TENANT)",
|
||||
"PCS_DIAGNOSTICS_WEBSERVICE_URL": "http://localhost:9006/v1",
|
||||
"PCS_AUTH_REQUIRED": "false",
|
||||
"PCS_AZUREBLOB_CONNSTRING": "$(PCS_AZUREBLOB_CONNSTRING)",
|
||||
"PCS_ACTION_EVENTHUB_CONNSTRING": "$(PCS_ACTION_EVENTHUB_CONNSTRING)",
|
||||
"PCS_ACTION_EVENTHUB_NAME": "$(PCS_ACTION_EVENTHUB_NAME)",
|
||||
"PCS_LOGICAPP_ENDPOINT_URL": "$(PCS_LOGICAPP_ENDPOINT_URL)",
|
||||
"PCS_SOLUTION_WEBSITE_URL": "$(PCS_SOLUTION_WEBSITE_URL)"
|
||||
"PCS_AAD_APPSECRET": "$(PCS_AAD_APPSECRET)"
|
||||
},
|
||||
"applicationUrl": "http://localhost:9004/v1/status"
|
||||
}
|
||||
|
|
|
@ -23,65 +23,61 @@ namespace Microsoft.Azure.IoTSolutions.DeviceTelemetry.WebService.Runtime
|
|||
public class Config : IConfig
|
||||
{
|
||||
private const string APPLICATION_KEY = "TelemetryService:";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservice_port";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservicePort";
|
||||
|
||||
private const string COSMOSDB_KEY = "TelemetryService:CosmosDb:";
|
||||
private const string COSMOSDB_CONNSTRING_KEY = COSMOSDB_KEY + "connstring";
|
||||
private const string COSMOSDB_CONNSTRING_KEY = COSMOSDB_KEY + "documentDBConnectionString";
|
||||
private const string COSMOSDB_RUS_KEY = COSMOSDB_KEY + "RUs";
|
||||
|
||||
private const string TIME_SERIES_KEY = APPLICATION_KEY + "TimeSeries:";
|
||||
private const string TIME_SERIES_FQDN = TIME_SERIES_KEY + "fqdn";
|
||||
private const string TIME_SERIES_FQDN = TIME_SERIES_KEY + "tsiDataAccessFQDN";
|
||||
private const string TIME_SERIES_AUTHORITY = TIME_SERIES_KEY + "authority";
|
||||
private const string TIME_SERIES_AUDIENCE = TIME_SERIES_KEY + "audience";
|
||||
private const string TIME_SERIES_EXPLORER_URL = TIME_SERIES_KEY + "explorer_url";
|
||||
private const string TIME_SERIES_API_VERSION = TIME_SERIES_KEY + "api_version";
|
||||
private const string TIME_SERIES_EXPLORER_URL = TIME_SERIES_KEY + "explorerUrl";
|
||||
private const string TIME_SERIES_API_VERSION = TIME_SERIES_KEY + "apiVersion";
|
||||
private const string TIME_SERIES_TIMEOUT = TIME_SERIES_KEY + "timeout";
|
||||
|
||||
private const string AAD_KEY = APPLICATION_KEY + "AzureActiveDirectory:";
|
||||
private const string AAD_TENANT = AAD_KEY + "tenant";
|
||||
private const string AAD_APP_ID = AAD_KEY + "app_id";
|
||||
private const string AAD_APP_SECRET = AAD_KEY + "app_secret";
|
||||
private const string AAD_TENANT = AAD_KEY + "aadTenantId";
|
||||
private const string AAD_APP_ID = AAD_KEY + "aadAppId";
|
||||
private const string AAD_APP_SECRET = AAD_KEY + "aadAppSecret";
|
||||
|
||||
private const string MESSAGES_DB_KEY = "TelemetryService:Messages:";
|
||||
private const string MESSAGES_DB_DATABASE_KEY = MESSAGES_DB_KEY + "database";
|
||||
private const string MESSAGES_DB_COLLECTION_KEY = MESSAGES_DB_KEY + "collection";
|
||||
private const string MESSAGES_STORAGE_TYPE = MESSAGES_DB_KEY + "storage_type";
|
||||
private const string MESSAGES_STORAGE_TYPE = MESSAGES_DB_KEY + "telemetryStorageType";
|
||||
|
||||
private const string ALARMS_DB_KEY = "TelemetryService:Alarms:";
|
||||
private const string ALARMS_DB_DATABASE_KEY = ALARMS_DB_KEY + "database";
|
||||
private const string ALARMS_DB_COLLECTION_KEY = ALARMS_DB_KEY + "collection";
|
||||
private const string ALARMS_DB_MAX_DELETE_RETRIES = ALARMS_DB_KEY + "max_delete_retries";
|
||||
private const string ALARMS_DB_MAX_DELETE_RETRIES = ALARMS_DB_KEY + "maxDeleteRetries";
|
||||
|
||||
private const string STORAGE_ADAPTER_KEY = "StorageAdapterService:";
|
||||
private const string STORAGE_ADAPTER_API_URL_KEY = STORAGE_ADAPTER_KEY + "webservice_url";
|
||||
private const string STORAGE_ADAPTER_API_TIMEOUT_KEY = STORAGE_ADAPTER_KEY + "webservice_timeout";
|
||||
|
||||
private const string USER_MANAGEMENT_KEY = "UserManagementService:";
|
||||
private const string USER_MANAGEMENT_URL_KEY = USER_MANAGEMENT_KEY + "webservice_url";
|
||||
|
||||
private const string DIAGNOSTICS_KEY = "DiagnosticsService:";
|
||||
private const string DIAGNOSTICS_URL_KEY = DIAGNOSTICS_KEY + "webservice_url";
|
||||
private const string DIAGNOSTICS_MAX_LOG_RETRIES = DIAGNOSTICS_KEY + "max_log_retries";
|
||||
private const string EXT_DEPENDENCIES_KEY = "ExternalDependencies:";
|
||||
private const string STORAGE_ADAPTER_API_URL_KEY = EXT_DEPENDENCIES_KEY + "storageAdapterWebServiceUrl";
|
||||
private const string STORAGE_ADAPTER_API_TIMEOUT_KEY = EXT_DEPENDENCIES_KEY + "storageAdapterWebserviceTimeout";
|
||||
private const string USER_MANAGEMENT_URL_KEY = EXT_DEPENDENCIES_KEY + "authWebServiceUrl";
|
||||
private const string DIAGNOSTICS_URL_KEY = EXT_DEPENDENCIES_KEY + "diagnosticsWebServiceUrl";
|
||||
private const string DIAGNOSTICS_MAX_LOG_RETRIES = EXT_DEPENDENCIES_KEY + "diagnosticsMaxLogRetries";
|
||||
|
||||
private const string CLIENT_AUTH_KEY = APPLICATION_KEY + "ClientAuth:";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "cors_whitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "auth_type";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "auth_required";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "corsWhitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "authType";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "authRequired";
|
||||
|
||||
private const string JWT_KEY = APPLICATION_KEY + "ClientAuth:JWT:";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowed_algorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "issuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "audience";
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clock_skew_seconds";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowedAlgorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "authIssuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "aadAppId";
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clockSkewSeconds";
|
||||
|
||||
private const string ACTIONS_KEY = "Actions:";
|
||||
private const string ACTIONS_EVENTHUB_NAME = ACTIONS_KEY + "event_hub_name";
|
||||
private const string ACTIONS_EVENTHUB_CONNSTRING = ACTIONS_KEY + "event_hub_connection_string";
|
||||
private const string ACTIONS_LOGICAPP_ENDPOINTURL = ACTIONS_KEY + "logic_app_endpoint_url";
|
||||
private const string ACTIONS_AZUREBLOB_CONNSTRING = ACTIONS_KEY + "blob_storage_connection_string";
|
||||
private const string ACTIONS_AZUREBLOB_CONTAINER = ACTIONS_KEY + "blob_storage_container";
|
||||
private const string SOLUTION_URL = ACTIONS_KEY + "solution_url";
|
||||
private const string TEMPLATE_FOLDER = ACTIONS_KEY + "template_folder";
|
||||
private const string ACTIONS_EVENTHUB_NAME = ACTIONS_KEY + "actionsEventHubName";
|
||||
private const string ACTIONS_EVENTHUB_CONNSTRING = ACTIONS_KEY + "actionsEventHubConnectionString";
|
||||
private const string ACTIONS_LOGICAPP_ENDPOINTURL = ACTIONS_KEY + "logicAppEndpointUrl";
|
||||
private const string ACTIONS_AZUREBLOB_CONNSTRING = ACTIONS_KEY + "storageConnectionString";
|
||||
private const string ACTIONS_AZUREBLOB_CONTAINER = ACTIONS_KEY + "storageContainer";
|
||||
private const string SOLUTION_URL = ACTIONS_KEY + "solutionWebsiteUrl";
|
||||
private const string TEMPLATE_FOLDER = ACTIONS_KEY + "templateFolder";
|
||||
|
||||
public int Port { get; }
|
||||
public IServicesConfig ServicesConfig { get; }
|
||||
|
|
|
@ -1,88 +1,81 @@
|
|||
[TelemetryService]
|
||||
webservice_port = 9004
|
||||
webservicePort = 9004
|
||||
; Note: in linux containers, the `data` folder is a symlink to /app/data
|
||||
; which can be mounted to inject custom rules
|
||||
rules_templates_folder = ./data/Rules/
|
||||
rulesTemplatesFolder = ./data/Rules/
|
||||
|
||||
[TelemetryService:CosmosDb]
|
||||
connstring = "${PCS_TELEMETRY_DOCUMENTDB_CONNSTRING}"
|
||||
documentDBConnectionString = ""
|
||||
; TODO: move to [messages] and [alarms] which could have different size requirements
|
||||
; https://github.com/Azure/remote-monitoring-services-dotnet/issues/114
|
||||
RUs = 400
|
||||
|
||||
|
||||
[TelemetryService:TimeSeries]
|
||||
fqdn = "${?PCS_TSI_FQDN}"
|
||||
tsiDataAccessFQDN = ""
|
||||
authority = "https://login.windows.net/"
|
||||
audience = "https://api.timeseries.azure.com/"
|
||||
explorer_url = "https://insights.timeseries.azure.com/"
|
||||
api_version = "2016-12-12"
|
||||
explorerUrl = "https://insights.timeseries.azure.com/"
|
||||
apiVersion = "2016-12-12"
|
||||
; Timeout value should be in ISO 8601 duration format,
|
||||
; for example "PT20S" and should be in the range 1-30s.
|
||||
timeout = "PT20S"
|
||||
|
||||
|
||||
[TelemetryService:AzureActiveDirectory]
|
||||
tenant = "${?PCS_AAD_TENANT}"
|
||||
app_id = "${?PCS_AAD_APPID}"
|
||||
app_secret = "${?PCS_AAD_APPSECRET}"
|
||||
aadTenantId = ""
|
||||
aadAppId = ""
|
||||
aadAppSecret = ""
|
||||
|
||||
|
||||
[TelemetryService:Messages]
|
||||
database = "pcs-iothub-stream"
|
||||
collection = "messages"
|
||||
; Supported values (not case sensitive): "cosmosdb", "tsi"
|
||||
storage_type = "${PCS_TELEMETRY_STORAGE_TYPE}"
|
||||
|
||||
telemetryStorageType = ""
|
||||
|
||||
[TelemetryService:Alarms]
|
||||
database = "pcs-iothub-stream"
|
||||
collection = "alarms"
|
||||
max_delete_retries = 3
|
||||
maxDeleteRetries = 3
|
||||
; Supported values (not case sensitive): "cosmosdb"
|
||||
storage_type = "cosmosdb"
|
||||
|
||||
|
||||
[StorageAdapterService]
|
||||
webservice_url = "${PCS_STORAGEADAPTER_WEBSERVICE_URL}"
|
||||
webservice_timeout = 10000
|
||||
|
||||
|
||||
[UserManagementService]
|
||||
webservice_url = "${PCS_AUTH_WEBSERVICE_URL}"
|
||||
|
||||
[DiagnosticsService]
|
||||
webservice_url = "${?PCS_DIAGNOSTICS_WEBSERVICE_URL}"
|
||||
max_log_retries = 3
|
||||
[ExternalDependencies]
|
||||
storageAdapterWebServiceUrl = ""
|
||||
storageAdapterWebserviceTimeout = 10000
|
||||
authWebServiceUrl = ""
|
||||
diagnosticsWebServiceUrl = ""
|
||||
diagnosticsMaxLogRetries = 3
|
||||
|
||||
[Actions]
|
||||
event_hub_name = "${PCS_ACTION_EVENTHUB_NAME}"
|
||||
event_hub_connection_string = "${PCS_ACTION_EVENTHUB_CONNSTRING}"
|
||||
logic_app_endpoint_url = "${PCS_LOGICAPP_ENDPOINT_URL}"
|
||||
blob_storage_connection_string = "${PCS_AZUREBLOB_CONNSTRING}"
|
||||
blob_storage_container = "actions-eventhub-container"
|
||||
solution_url = "${PCS_SOLUTION_WEBSITE_URL}"
|
||||
template_folder = ./data/
|
||||
actionsEventHubName = ""
|
||||
actionsEventHubConnectionString = ""
|
||||
logicAppEndpointUrl = ""
|
||||
storageConnectionString = ""
|
||||
storageContainer = "actions-eventhub-container"
|
||||
solutionWebsiteUrl = ""
|
||||
templateFolder = ./data/
|
||||
|
||||
|
||||
[TelemetryService:ClientAuth]
|
||||
;; Current auth type, only "JWT" is currently supported.
|
||||
auth_type="JWT"
|
||||
authType="JWT"
|
||||
;; This can be changed to false, for example during development,
|
||||
;; to allow invalid/missing authorizations.
|
||||
;; Default: true
|
||||
auth_required="${?PCS_AUTH_REQUIRED}"
|
||||
authRequired=""
|
||||
;; Can be used when running services on multiple hostnames and/or ports
|
||||
;; e.g. "{ 'origins': ['*'], 'methods': ['*'], 'headers': ['*'] }" to allow everything.
|
||||
;; Comment it or leave it empty to disable CORS.
|
||||
;; Default: empty
|
||||
cors_whitelist = "${?PCS_CORS_WHITELIST}"
|
||||
corsWhitelist = ""
|
||||
|
||||
|
||||
[TelemetryService:ClientAuth:JWT]
|
||||
; Trusted algorithms
|
||||
; Default: RS256, RS384, RS512
|
||||
allowed_algorithms="RS256"
|
||||
allowedAlgorithms="RS256"
|
||||
; Identifies the security token service (STS) that constructs and returns the token.
|
||||
; In the tokens that Azure AD returns, the issuer is sts.windows.net. The GUID in
|
||||
; the Issuer claim value is the tenant ID of the Azure AD directory. The tenant ID
|
||||
|
@ -91,15 +84,19 @@ allowed_algorithms="RS256"
|
|||
; When using Azure Active Directory, the format of the Issuer is:
|
||||
; https://sts.windows.net/<tenant Id>/
|
||||
; example: issuer="https://sts.windows.net/fa01ade2-2365-4dd1-a084-a6ef027090fc/"
|
||||
issuer="${?PCS_AUTH_ISSUER}"
|
||||
authIssuer=""
|
||||
; Used to verify that tokens are issued to be given to this service
|
||||
; Also referenced as "Application Id" and "Resource Id"
|
||||
; example: audience="2814e709-6a0e-4861-9594-d3b6e2b81331"
|
||||
audience="${?PCS_AUTH_AUDIENCE}"
|
||||
aadAppId=""
|
||||
; When validating the token expiration, allows some clock skew
|
||||
; Default: 2 minutes
|
||||
clock_skew_seconds = 300
|
||||
clockSkewSeconds = 300
|
||||
|
||||
[KeyVault]
|
||||
aadAppId = ${PCS_AAD_APPID}
|
||||
aadAppSecret = ${PCS_AAD_APPSECRET}
|
||||
name = ${PCS_KEYVAULT_NAME}
|
||||
|
||||
; For more information about ASP.NET logging see
|
||||
; https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging
|
||||
|
|
|
@ -16,25 +16,9 @@ run_container() {
|
|||
|
||||
echo "Starting Telemetry service..."
|
||||
docker run -it -p 9004:9004 \
|
||||
-e PCS_AUTH_WEBSERVICE_URL \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
|
||||
-e PCS_DIAGNOSTICS_WEBSERVICE_URL \
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_AUTH_REQUIRED \
|
||||
-e PCS_CORS_WHITELIST \
|
||||
-e PCS_APPLICATION_SECRET \
|
||||
-e PCS_AAD_TENANT \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
-e PCS_TELEMETRY_STORAGE_TYPE \
|
||||
-e PCS_TSI_FQDN \
|
||||
-e PCS_AZUREBLOB_CONNSTRING \
|
||||
-e PCS_ACTION_EVENTHUB_CONNSTRING \
|
||||
-e PCS_ACTION_EVENTHUB_NAME \
|
||||
-e PCS_LOGICAPP_ENDPOINT_URL \
|
||||
-e PCS_SOLUTION_WEBSITE_URL \
|
||||
"$DOCKER_IMAGE:testing"
|
||||
}
|
||||
|
||||
|
|
|
@ -21,25 +21,9 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
|
|||
:: Start the application
|
||||
echo Starting Telemetry service...
|
||||
docker run -it -p 9004:9004 ^
|
||||
-e PCS_AUTH_WEBSERVICE_URL ^
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
|
||||
-e PCS_DIAGNOSTICS_WEBSERVICE_URL ^
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_AUTH_REQUIRED ^
|
||||
-e PCS_CORS_WHITELIST ^
|
||||
-e PCS_APPLICATION_SECRET ^
|
||||
-e PCS_AAD_TENANT ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
-e PCS_TELEMETRY_STORAGE_TYPE ^
|
||||
-e PCS_TSI_FQDN ^
|
||||
-e PCS_AZUREBLOB_CONNSTRING ^
|
||||
-e PCS_ACTION_EVENTHUB_CONNSTRING ^
|
||||
-e PCS_ACTION_EVENTHUB_NAME ^
|
||||
-e PCS_LOGICAPP_ENDPOINT_URL ^
|
||||
-e PCS_SOLUTION_WEBSITE_URL ^
|
||||
%DOCKER_IMAGE%:testing
|
||||
|
||||
:: - - - - - - - - - - - - - -
|
||||
|
|
|
@ -1,97 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# Some settings are used to connect to an external dependency, e.g. Azure IoT Hub and IoT Hub Manager API
|
||||
# Depending on which settings and which dependencies are needed, edit the list of variables checked
|
||||
|
||||
# Before checking all the env vars, detect whether secrets, usually encrypted, are available or not.
|
||||
# Secrets are not available when building a pull request, so the script will not check for those.
|
||||
detect_secrets() {
|
||||
SECRETS_AVAILABLE="true"
|
||||
if [[ "$TRAVIS_PULL_REQUEST" != "" && "$TRAVIS_PULL_REQUEST" != "false" ]]; then
|
||||
SECRETS_AVAILABLE="false"
|
||||
echo "Warning: secrets and encrypted variables are not available when testing pull requests."
|
||||
fi
|
||||
}
|
||||
|
||||
detect_secrets
|
||||
|
||||
if [[ -z "$PCS_TELEMETRY_DOCUMENTDB_CONNSTRING" && "$SECRETS_AVAILABLE" = "true" ]]; then
|
||||
echo "Error: the PCS_TELEMETRY_DOCUMENTDB_CONNSTRING environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_STORAGEADAPTER_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_STORAGEADAPTER_WEBSERVICE_URL environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AUTH_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_AUTH_WEBSERVICE_URL environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AUTH_ISSUER" ]]; then
|
||||
echo "Error: the PCS_AUTH_ISSUER environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AUTH_AUDIENCE" ]]; then
|
||||
echo "Error: the PCS_AUTH_AUDIENCE environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_TELEMETRY_STORAGE_TYPE" ]]; then
|
||||
echo "Error: the PCS_TELEMETRY_STORAGE_TYPE environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# The settings below are for Time Series Insights. If your deployment does not use
|
||||
# Time Series Insights they are safe to remove.
|
||||
|
||||
if [[ -z "$PCS_AAD_TENANT" ]]; then
|
||||
echo "Error: the PCS_AAD_TENANT environment variable is not defined."
|
||||
exit -1
|
||||
if [[ -z "$PCS_KEYVAULT_NAME" ]]; then
|
||||
echo "Error: the PCS_KEYVAULT_NAME environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AAD_APPID" ]]; then
|
||||
echo "Error: the PCS_AAD_APPID environment variable is not defined."
|
||||
exit -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AAD_APPSECRET" ]]; then
|
||||
echo "Error: the PCS_AAD_APPSECRET environment variable is not defined."
|
||||
exit -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_TSI_FQDN" ]]; then
|
||||
echo "Error: the PCS_TSI_FQDN environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Settings for actions
|
||||
if [[ -z "$PCS_ACTION_EVENTHUB_NAME" ]]; then
|
||||
echo "Error: the PCS_ACTION_EVENTHUB_NAME environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_ACTION_EVENTHUB_CONNSTRING" ]]; then
|
||||
echo "Error: the PCS_ACTION_EVENTHUB_CONNSTRING environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_LOGICAPP_ENDPOINT_URL" ]]; then
|
||||
echo "Error: the PCS_LOGICAPP_ENDPOINT_URL environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AZUREBLOB_CONNSTRING" ]]; then
|
||||
echo "Error: the PCS_AZUREBLOB_CONNSTRING environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_SOLUTION_WEBSITE_URL" ]]; then
|
||||
echo "Error: the PCS_SOLUTION_WEBSITE_URL environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
|
|
|
@ -2,44 +2,8 @@
|
|||
|
||||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
:: Some settings are used to connect to an external dependency, e.g. Azure IoT Hub and IoT Hub Manager API
|
||||
:: Depending on which settings and which dependencies are needed, edit the list of variables checked
|
||||
|
||||
IF "%PCS_TELEMETRY_DOCUMENTDB_CONNSTRING%" == "" (
|
||||
echo Error: the PCS_TELEMETRY_DOCUMENTDB_CONNSTRING environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_STORAGEADAPTER_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_STORAGEADAPTER_WEBSERVICE_URL environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AUTH_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_AUTH_WEBSERVICE_URL environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AUTH_ISSUER%" == "" (
|
||||
echo Error: the PCS_AUTH_ISSUER environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AUTH_AUDIENCE%" == "" (
|
||||
echo Error: the PCS_AUTH_AUDIENCE environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_TELEMETRY_STORAGE_TYPE%" == "" (
|
||||
echo Error: the PCS_TELEMETRY_STORAGE_TYPE environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
:: The settings below are for Time Series Insights. If your deployment does not use
|
||||
:: Time Series Insights they are safe to remove.
|
||||
|
||||
IF "%PCS_AAD_TENANT%" == "" (
|
||||
echo Error: the PCS_AAD_TENANT environment variable is not defined.
|
||||
IF "%PCS_KEYVAULT_NAME%" == "" (
|
||||
echo Error: the PCS_KEYVAULT_NAME environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
|
@ -53,36 +17,4 @@ IF "%PCS_AAD_APPSECRET%" == "" (
|
|||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_TSI_FQDN%" == "" (
|
||||
echo Error: the PCS_TSI_FQDN environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
:: Settings for actions
|
||||
|
||||
IF "%PCS_ACTION_EVENTHUB_NAME%" == "" (
|
||||
echo Error: the PCS_ACTION_EVENTHUB_NAME environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_ACTION_EVENTHUB_CONNSTRING%" == "" (
|
||||
echo Error: the PCS_ACTION_EVENTHUB_CONNSTRING environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_LOGICAPP_ENDPOINT_URL%" == "" (
|
||||
echo Error: the PCS_LOGICAPP_ENDPOINT_URL environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AZUREBLOB_CONNSTRING%" == "" (
|
||||
echo Error: the PCS_AZUREBLOB_CONNSTRING environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_SOLUTION_WEBSITE_URL%" == "" (
|
||||
echo Error: the PCS_SOLUTION_WEBSITE_URL environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
endlocal
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# Usage: source ./scripts/env-vars-setup
|
||||
#
|
||||
# IMPORTANT NOTES:
|
||||
# * use "source" in front of the script path, so that variables are exported in your shell
|
||||
# * the variables are set only in the current shell, run this script every time, or automate
|
||||
# the setup using your `~/.bash_profile`.
|
||||
|
||||
# Prepare the environment variables used by the application.
|
||||
|
||||
# Some settings are used to connect to an external dependency, e.g. Azure IoT Hub and IoT Hub Manager API
|
||||
# Depending on which settings and which dependencies are needed, edit the list of variables
|
||||
|
||||
# see: Shared access policies => key name => Connection string
|
||||
export PCS_TELEMETRY_DOCUMENTDB_CONNSTRING="..."
|
||||
|
||||
# The URL where IoT Hub Manager web service is listening
|
||||
export PCS_STORAGEADAPTER_WEBSERVICE_URL="http://127.0.0.1:9022/v1"
|
||||
|
||||
# The URL where Authentication web service is listening
|
||||
export PCS_AUTH_WEBSERVICE_URL="http://127.0.0.1:9001/v1"
|
||||
|
||||
# The OpenId tokens issuer URL, e.g. https://sts.windows.net/12000000-3400-5600-0000-780000000000/
|
||||
export PCS_AUTH_ISSUER="{enter the token issuer URL here}"
|
||||
|
||||
# The intended audience of the tokens, e.g. your Client Id
|
||||
export PCS_AUTH_AUDIENCE="{enter the tokens audience here}"
|
||||
|
||||
# The tenant for the Azure Active Directory application
|
||||
# see: Azure Portal => Azure Active Directory => Properties => Directory ID
|
||||
export PCS_AAD_TENANT="{enter the Azure Active Directory Tenant for the application here}"
|
||||
|
||||
# The Application ID registered with Azure Active Directory
|
||||
# see: Azure Portal => Azure Active Directory => App Registrations => Your App => Application ID
|
||||
export PCS_AAD_APPID="{enter Azure Active Directory application ID here}"
|
||||
|
||||
# The Application Secret for your Azure Active Directory Application
|
||||
# see: Azure Portal => Azure Active Directory => App Registrations => Your App => Settings => Passwords
|
||||
export PCS_AAD_APPSECRET="{enter your application secret here}"
|
||||
|
||||
# The storage type for telemetry messages. Default is "tsi". Allowed values: ["cosmosdb", "tsi"]
|
||||
export PCS_TELEMETRY_STORAGE_TYPE="tsi"
|
||||
|
||||
# The FQDN (Fully Qualified Domain Name) for the Time Series endpoint
|
||||
# see: Azure Portal => Your Resource Group => Time Series Insights Environment => Data Access FQDN
|
||||
export PCS_TSI_FQDN="{enter your Time Series FQDN here}"
|
||||
|
||||
# The name of the event hub that alarms with actions are written to
|
||||
export PCS_ACTION_EVENTHUB_NAME="{Enter event hub name here}"
|
||||
|
||||
# The connection string of the event hub namespace that alarms with actions are written to
|
||||
# see: Azure Portal => Your resource group => your event hub namespace => Shared access policies
|
||||
export PCS_ACTION_EVENTHUB_CONNSTRING="{Endpoint=sb://....servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=...}"
|
||||
|
||||
# Endpoint of logic app workflow.
|
||||
# See Azure Portal => Your resource group => Your Logic App => Logic App Designer => When a Http Request is received => HTTP POST URL
|
||||
export PCS_LOGICAPP_ENDPOINT_URL="{Enter endpoint here}"
|
||||
|
||||
# Azure Blob Storage Connection String
|
||||
# See Azure Portal => Your resource group => Your Storage Account => Access keys => Connection String
|
||||
export PCS_AZUREBLOB_CONNSTRING="{Enter connection string here}"
|
||||
|
||||
# Url of your solution
|
||||
export PCS_SOLUTION_WEBSITE_URL="{Enter solution url}"
|
|
@ -1,58 +0,0 @@
|
|||
:: Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
:: Prepare the environment variables used by the application.
|
||||
|
||||
:: Some settings are used to connect to an external dependency, e.g. Azure IoT Hub and IoT Hub Manager API
|
||||
:: Depending on which settings and which dependencies are needed, edit the list of variables
|
||||
|
||||
:: see: Shared access policies => key name => Connection string
|
||||
SETX PCS_TELEMETRY_DOCUMENTDB_CONNSTRING "..."
|
||||
|
||||
:: The URL where IoT Hub Manager web service is listening
|
||||
SETX PCS_STORAGEADAPTER_WEBSERVICE_URL "http://127.0.0.1:9022/v1"
|
||||
|
||||
:: Endpoint to reach the authentication service
|
||||
SETX PCS_AUTH_WEBSERVICE_URL "http://127.0.0.1:9001/v1"
|
||||
|
||||
:: The OpenId tokens issuer URL, e.g. https://sts.windows.net/12000000-3400-5600-0000-780000000000/
|
||||
SETX PCS_AUTH_ISSUER "{enter the token issuer URL here}"
|
||||
|
||||
:: The intended audience of the tokens, e.g. your Client Id
|
||||
SETX PCS_AUTH_AUDIENCE "{enter the tokens audience here}"
|
||||
|
||||
:: The tenant for the Azure Active Directory application
|
||||
:: see: Azure Portal => Azure Active Directory => Properties => Directory ID
|
||||
SETX PCS_AAD_TENANT="{enter the Azure Active Directory Tenant for the application here}"
|
||||
|
||||
:: The Application ID registered with Azure Active Directory
|
||||
:: see: Azure Portal => Azure Active Directory => App Registrations => Your App => Application ID
|
||||
SETX PCS_AAD_APPID="{enter Azure Active Directory application ID here}"
|
||||
|
||||
:: The Application Secret for your Azure Active Directory Application
|
||||
:: see: Azure Portal => Azure Active Directory => App Registrations => Your App => Settings => Passwords
|
||||
SETX PCS_AAD_APPSECRET="{enter your application secret here}"
|
||||
|
||||
:: The storage type for telemetry messages. Default is "tsi". Allowed values: ["cosmosdb", "tsi"]
|
||||
SETX PCS_TELEMETRY_STORAGE_TYPE="tsi"
|
||||
|
||||
:: The FQDN (Fully Qualified Domain Name) for the Time Series endpoint
|
||||
:: see: Azure Portal => Your Resource Group => Time Series Insights Environment => Data Access FQDN
|
||||
SETX PCS_TSI_FQDN="{enter your Time Series FQDN here}"
|
||||
|
||||
:: The name of the event hub that alarms with actions are written to
|
||||
SETX PCS_ACTION_EVENTHUB_NAME "{Enter event hub name here}"
|
||||
|
||||
:: The connection string of the event hub namespace that alarms with actions are written to
|
||||
:: see: Azure Portal => Your resource group => your event hub namespace => Shared access policies
|
||||
SETX PCS_ACTION_EVENTHUB_CONNSTRING "{Endpoint=sb://....servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=...}"
|
||||
|
||||
:: Endpoint of logic app workflow.
|
||||
:: See Azure Portal => Your resource group => Your Logic App => Logic App Designer => When a Http Request is received => HTTP POST URL
|
||||
SETX PCS_LOGICAPP_ENDPOINT_URL "{Enter endpoint here}"
|
||||
|
||||
:: Azure Blob Storage Connection String
|
||||
:: See Azure Portal => Your resource group => Your Storage Account => Access keys => Connection String
|
||||
SETX PCS_AZUREBLOB_CONNSTRING "{Enter connection string here}"
|
||||
|
||||
:: Url of your solution
|
||||
SETX PCS_SOLUTION_WEBSITE_URL "{Enter solution url}"
|
|
@ -70,21 +70,9 @@ run_in_sandbox() {
|
|||
# edit the list of variables.
|
||||
docker run -it \
|
||||
-p 9004:9004 \
|
||||
-e PCS_TELEMETRY_DOCUMENTDB_CONNSTRING \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
|
||||
-e PCS_AUTH_WEBSERVICE_URL \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_AAD_TENANT \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
-e PCS_TELEMETRY_STORAGE_TYPE \
|
||||
-e PCS_TSI_FQDN \
|
||||
-e PCS_AZUREBLOB_CONNSTRING \
|
||||
-e PCS_ACTION_EVENTHUB_CONNSTRING \
|
||||
-e PCS_ACTION_EVENTHUB_NAME \
|
||||
-e PCS_LOGICAPP_ENDPOINT_URL \
|
||||
-e PCS_SOLUTION_WEBSITE_URL \
|
||||
-v "$PCS_CACHE/sandbox/.config:/root/.config" \
|
||||
-v "$PCS_CACHE/sandbox/.dotnet:/root/.dotnet" \
|
||||
-v "$PCS_CACHE/sandbox/.nuget:/root/.nuget" \
|
||||
|
|
|
@ -63,21 +63,9 @@ IF "%1"=="--in-sandbox" GOTO :RunInSandbox
|
|||
:: Start the sandbox and run the service
|
||||
docker run -it ^
|
||||
-p 9004:9004 ^
|
||||
-e "PCS_TELEMETRY_DOCUMENTDB_CONNSTRING=%PCS_TELEMETRY_DOCUMENTDB_CONNSTRING%" ^
|
||||
-e "PCS_STORAGEADAPTER_WEBSERVICE_URL=%PCS_STORAGEADAPTER_WEBSERVICE_URL%" ^
|
||||
-e PCS_AUTH_WEBSERVICE_URL ^
|
||||
-e "PCS_AUTH_ISSUER=%PCS_AUTH_ISSUER%" ^
|
||||
-e "PCS_AUTH_AUDIENCE=%PCS_AUTH_AUDIENCE%" ^
|
||||
-e "PCS_AAD_TENANT" ^
|
||||
-e "PCS_AAD_APPID" ^
|
||||
-e "PCS_AAD_APPSECRET" ^
|
||||
-e "PCS_TELEMETRY_STORAGE_TYPE" ^
|
||||
-e "PCS_TSI_FQDN" ^
|
||||
-e "PCS_AZUREBLOB_CONNSTRING" ^
|
||||
-e "PCS_ACTION_EVENTHUB_CONNSTRING" ^
|
||||
-e "PCS_ACTION_EVENTHUB_NAME" ^
|
||||
-e "PCS_LOGICAPP_ENDPOINT_URL" ^
|
||||
-e "PCS_SOLUTION_WEBSITE_URL" ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
-v %PCS_CACHE%\sandbox\.config:/root/.config ^
|
||||
-v %PCS_CACHE%\sandbox\.dotnet:/root/.dotnet ^
|
||||
-v %PCS_CACHE%\sandbox\.nuget:/root/.nuget ^
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
# Note: Windows Bash doesn't support shebang extra params
|
||||
set -e
|
||||
|
||||
# Example usage (see "travis help" for more information):
|
||||
# travis help
|
||||
# travis login --pro
|
||||
# travis whoami --pro
|
||||
# travis accounts --pro
|
||||
# travis history
|
||||
# travis monitor --pro
|
||||
# travis settings
|
||||
# travis show
|
||||
# travis status
|
||||
# travis token --pro
|
||||
# travis whatsup --pro
|
||||
|
||||
set -e
|
||||
APP_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )/"
|
||||
cd $APP_HOME
|
||||
|
||||
mkdir -p .travis
|
||||
|
||||
docker run -it \
|
||||
-v $APP_HOME/.travis:/root/.travis \
|
||||
-v $APP_HOME:/opt/code \
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh $*
|
||||
|
||||
set +e
|
|
@ -1,30 +0,0 @@
|
|||
:: Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
:: Example usage (see "travis help" for more information:
|
||||
:: travis help
|
||||
:: travis login --pro
|
||||
:: travis whoami --pro
|
||||
:: travis accounts --pro
|
||||
:: travis history
|
||||
:: travis monitor --pro
|
||||
:: travis settings
|
||||
:: travis show
|
||||
:: travis status
|
||||
:: travis token --pro
|
||||
:: travis whatsup --pro
|
||||
|
||||
:: strlen("\scripts\") => 9
|
||||
SET APP_HOME=%~dp0
|
||||
SET APP_HOME=%APP_HOME:~0,-9%
|
||||
cd %APP_HOME%
|
||||
|
||||
mkdir .travis 2>NUL
|
||||
|
||||
docker run -it ^
|
||||
-v %APP_HOME%\.travis:/root/.travis ^
|
||||
-v %APP_HOME%:/opt/code ^
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh %*
|
||||
|
||||
endlocal
|
|
@ -23,28 +23,38 @@ namespace Microsoft.Azure.IoTSolutions.IotHubManager.Services.Runtime
|
|||
private readonly IConfigurationRoot configuration;
|
||||
private readonly ILogger log;
|
||||
|
||||
// Key Vault
|
||||
private KeyVault keyVault;
|
||||
|
||||
// Constants
|
||||
private const string CLIENT_ID = "KeyVault:aadAppId";
|
||||
private const string CLIENT_SECRET = "KeyVault:aadAppSecret";
|
||||
private const string KEY_VAULT_NAME = "KeyVault:name";
|
||||
|
||||
public ConfigData(ILogger logger)
|
||||
{
|
||||
this.log = logger;
|
||||
|
||||
// More info about configuration at
|
||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration
|
||||
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true);
|
||||
this.configuration = configurationBuilder.Build();
|
||||
|
||||
// Set up Key Vault
|
||||
this.SetUpKeyVault();
|
||||
}
|
||||
|
||||
public string GetString(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
var value = this.GetSecrets(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool GetBool(string key, bool defaultValue = false)
|
||||
{
|
||||
var value = this.GetString(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
var value = this.GetSecrets(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
|
||||
var knownTrue = new HashSet<string> { "true", "t", "yes", "y", "1", "-1" };
|
||||
var knownFalse = new HashSet<string> { "false", "f", "no", "n", "0" };
|
||||
|
@ -59,7 +69,7 @@ namespace Microsoft.Azure.IoTSolutions.IotHubManager.Services.Runtime
|
|||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(this.GetString(key, defaultValue.ToString()));
|
||||
return Convert.ToInt32(this.GetSecrets(key, defaultValue.ToString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -67,6 +77,49 @@ namespace Microsoft.Azure.IoTSolutions.IotHubManager.Services.Runtime
|
|||
}
|
||||
}
|
||||
|
||||
private void SetUpKeyVault()
|
||||
{
|
||||
var clientId = this.GetEnvironmentVariable(CLIENT_ID, string.Empty);
|
||||
var clientSecret = this.GetEnvironmentVariable(CLIENT_SECRET, string.Empty);
|
||||
var keyVaultName = this.GetEnvironmentVariable(KEY_VAULT_NAME, string.Empty);
|
||||
|
||||
// Initailize key vault
|
||||
this.keyVault = new KeyVault(keyVaultName, clientId, clientSecret, this.log);
|
||||
}
|
||||
|
||||
private string GetSecrets(string key, string defaultValue = "")
|
||||
{
|
||||
string value = string.Empty;
|
||||
|
||||
value = this.GetLocalVariable(key, defaultValue);
|
||||
|
||||
// If secrets are not found locally, search in Key-Vault
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
log.Warn($"Value for secret {key} not found in local env. " +
|
||||
$" Trying to get the secret from KeyVault.", () => { });
|
||||
value = this.keyVault.GetSecret(key);
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
private string GetSecretsFromKeyVault(string key) {
|
||||
return this.keyVault.GetSecret(key);
|
||||
}
|
||||
|
||||
private string GetLocalVariable(string key, string defaultValue = "")
|
||||
{
|
||||
return this.configuration.GetValue(key, defaultValue);
|
||||
}
|
||||
|
||||
public string GetEnvironmentVariable(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void ReplaceEnvironmentVariables(ref string value, string defaultValue = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return;
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
using Microsoft.Azure.IoTSolutions.IotHubManager.Services.Diagnostics;
|
||||
using Microsoft.Azure.KeyVault;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.IotHubManager.Services.Runtime
|
||||
{
|
||||
public class KeyVault
|
||||
{
|
||||
|
||||
// Key Vault details and access
|
||||
private readonly string name;
|
||||
private readonly string clientId;
|
||||
private readonly string clientSecret;
|
||||
private ILogger log;
|
||||
|
||||
// Key Vault Client
|
||||
private readonly KeyVaultClient keyVaultClient;
|
||||
|
||||
// Constants
|
||||
private const string KEY_VAULT_URI = "https://{0}.vault.azure.net/secrets/{1}";
|
||||
|
||||
public KeyVault(
|
||||
string name,
|
||||
string clientId,
|
||||
string clientSecret,
|
||||
ILogger logger)
|
||||
{
|
||||
this.name = name;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.log = logger;
|
||||
this.keyVaultClient = new KeyVaultClient(
|
||||
new KeyVaultClient.AuthenticationCallback(this.GetToken));
|
||||
}
|
||||
|
||||
public string GetSecret(string secretKey)
|
||||
{
|
||||
secretKey = secretKey.Split(':').Last();
|
||||
var uri = string.Format(KEY_VAULT_URI, this.name, secretKey);
|
||||
|
||||
try
|
||||
{
|
||||
return this.keyVaultClient.GetSecretAsync(uri).Result.Value;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
this.log.Error($"Secret {secretKey} not found in Key Vault.", () => { });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//the method that will be provided to the KeyVaultClient
|
||||
private async Task<string> GetToken(string authority, string resource, string scope)
|
||||
{
|
||||
var authContext = new AuthenticationContext(authority);
|
||||
ClientCredential clientCred = new ClientCredential(this.clientId, this.clientSecret);
|
||||
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
this.log.Debug($"Failed to obtain authentication token from key vault.", () => { });
|
||||
throw new System.InvalidOperationException("Failed to obtain the JWT token");
|
||||
}
|
||||
|
||||
return result.AccessToken;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,5 +9,7 @@
|
|||
<PackageReference Include="Microsoft.Azure.Devices" Version="1.17.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.Azure.KeyVault" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -13,9 +13,9 @@
|
|||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:9002/v1/status",
|
||||
"environmentVariables": {
|
||||
"PCS_AUTH_WEBSERVICE_URL": "http://localhost:9001/v1",
|
||||
"PCS_IOTHUB_CONNSTRING": "$(PCS_IOTHUB_CONNSTRING)",
|
||||
"PCS_STORAGEADAPTER_WEBSERVICE_URL": "http://localhost:9022/v1"
|
||||
"PCS_KEYVAULT_NAME": "$(PCS_KEYVAULT_NAME)",
|
||||
"PCS_AAD_APPID": "$(PCS_AAD_APPID)",
|
||||
"PCS_AAD_APPSECRET": "$(PCS_AAD_APPSECRET)"
|
||||
},
|
||||
"applicationUrl": "http://localhost:9002/v1/status"
|
||||
}
|
||||
|
|
|
@ -22,29 +22,27 @@ namespace Microsoft.Azure.IoTSolutions.IotHubManager.WebService.Runtime
|
|||
public class Config : IConfig
|
||||
{
|
||||
private const string APPLICATION_KEY = "IothubManagerService:";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservice_port";
|
||||
private const string IOTHUB_CONNSTRING_KEY = APPLICATION_KEY + "iothub_connstring";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservicePort";
|
||||
private const string IOTHUB_CONNSTRING_KEY = APPLICATION_KEY + "iotHubConnectionString";
|
||||
private const string DEVICE_PROPERTIES_KEY = APPLICATION_KEY + "DevicePropertiesCache:";
|
||||
private const string DEVICE_PROPERTIES_WHITELIST_KEY = DEVICE_PROPERTIES_KEY + "whitelist";
|
||||
private const string DEVICE_PROPERTIES_TTL_KEY = DEVICE_PROPERTIES_KEY + "TTL";
|
||||
private const string DEVICE_PROPERTIES_REBUILD_TIMEOUT_KEY = DEVICE_PROPERTIES_KEY + "rebuild_timeout";
|
||||
private const string DEVICE_PROPERTIES_REBUILD_TIMEOUT_KEY = DEVICE_PROPERTIES_KEY + "rebuildTimeout";
|
||||
|
||||
private const string STORAGE_ADAPTER_KEY = "StorageAdapterService:";
|
||||
private const string STORAGE_ADAPTER_URL_KEY = STORAGE_ADAPTER_KEY + "webservice_url";
|
||||
|
||||
private const string USER_MANAGEMENT_KEY = "UserManagementService:";
|
||||
private const string USER_MANAGEMENT_URL_KEY = USER_MANAGEMENT_KEY + "webservice_url";
|
||||
private const string EXTERNAL_DEPENDENCIES = "ExternalDependencies:";
|
||||
private const string STORAGE_ADAPTER_URL_KEY = EXTERNAL_DEPENDENCIES + "storageAdapterWebServiceUrl";
|
||||
private const string USER_MANAGEMENT_URL_KEY = EXTERNAL_DEPENDENCIES + "authWebServiceUrl";
|
||||
|
||||
private const string CLIENT_AUTH_KEY = APPLICATION_KEY + "ClientAuth:";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "cors_whitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "auth_type";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "auth_required";
|
||||
private const string CORS_WHITELIST_KEY = CLIENT_AUTH_KEY + "corsWhitelist";
|
||||
private const string AUTH_TYPE_KEY = CLIENT_AUTH_KEY + "authType";
|
||||
private const string AUTH_REQUIRED_KEY = CLIENT_AUTH_KEY + "authRequired";
|
||||
|
||||
private const string JWT_KEY = APPLICATION_KEY + "ClientAuth:JWT:";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowed_algorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "issuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "audience";
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clock_skew_seconds";
|
||||
private const string JWT_ALGOS_KEY = JWT_KEY + "allowedAlgorithms";
|
||||
private const string JWT_ISSUER_KEY = JWT_KEY + "authIssuer";
|
||||
private const string JWT_AUDIENCE_KEY = JWT_KEY + "aadAppId";
|
||||
private const string JWT_CLOCK_SKEW_KEY = JWT_KEY + "clockSkewSeconds";
|
||||
|
||||
public int Port { get; }
|
||||
public IServicesConfig ServicesConfig { get; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[IothubManagerService]
|
||||
webservice_port = 9002
|
||||
iothub_connstring = "${PCS_IOTHUB_CONNSTRING}"
|
||||
webservicePort = 9002
|
||||
iotHubConnectionString = ""
|
||||
|
||||
[IothubManagerService:DevicePropertiesCache]
|
||||
; This is the list of device properties that will be whiletlisted from the list of device properties received from CosmosDB
|
||||
|
@ -8,32 +8,30 @@ whitelist = "tags.*, reported.Protocol, reported.SupportedMethods, reported.Devi
|
|||
; Expiration time for device properties in seconds
|
||||
TTL = 3600
|
||||
; How long, in seconds, to timeout before trying to build device properties again
|
||||
rebuild_timeout = 20
|
||||
rebuildTimeout = 20
|
||||
|
||||
[StorageAdapterService]
|
||||
webservice_url = "${PCS_STORAGEADAPTER_WEBSERVICE_URL}"
|
||||
|
||||
[UserManagementService]
|
||||
webservice_url = "${PCS_AUTH_WEBSERVICE_URL}"
|
||||
[ExternalDependencies]
|
||||
storageAdapterWebServiceUrl = ""
|
||||
authWebServiceUrl = ""
|
||||
|
||||
[IothubManagerService:ClientAuth]
|
||||
;; Current auth type, only "JWT" is currently supported.
|
||||
auth_type="JWT"
|
||||
authType="JWT"
|
||||
;; This can be changed to false, for example during development,
|
||||
;; to allow invalid/missing authorizations.
|
||||
;; Default: true
|
||||
auth_required="${?PCS_AUTH_REQUIRED}"
|
||||
authRequired=""
|
||||
;; Can be used when running services on multiple hostnames and/or ports
|
||||
;; e.g. "{ 'origins': ['*'], 'methods': ['*'], 'headers': ['*'] }" to allow everything.
|
||||
;; Comment it or leave it empty to disable CORS.
|
||||
;; Default: empty
|
||||
cors_whitelist = "${?PCS_CORS_WHITELIST}"
|
||||
corsWhitelist = ""
|
||||
|
||||
|
||||
[IothubManagerService:ClientAuth:JWT]
|
||||
; Trusted algorithms
|
||||
; Default: RS256, RS384, RS512
|
||||
allowed_algorithms="RS256"
|
||||
allowedAlgorithms="RS256"
|
||||
; Identifies the security token service (STS) that constructs and returns the token.
|
||||
; In the tokens that Azure AD returns, the issuer is sts.windows.net. The GUID in
|
||||
; the Issuer claim value is the tenant ID of the Azure AD directory. The tenant ID
|
||||
|
@ -42,15 +40,19 @@ allowed_algorithms="RS256"
|
|||
; When using Azure Active Directory, the format of the Issuer is:
|
||||
; https://sts.windows.net/<tenant Id>/
|
||||
; example: issuer="https://sts.windows.net/fa01ade2-2365-4dd1-a084-a6ef027090fc/"
|
||||
issuer="${?PCS_AUTH_ISSUER}"
|
||||
authIssuer=""
|
||||
; Used to verify that tokens are issued to be given to this service
|
||||
; Also referenced as "Application Id" and "Resource Id"
|
||||
; example: audience="2814e709-6a0e-4861-9594-d3b6e2b81331"
|
||||
audience="${?PCS_AUTH_AUDIENCE}"
|
||||
aadAppId=""
|
||||
; When validating the token expiration, allows some clock skew
|
||||
; Default: 2 minutes
|
||||
clock_skew_seconds = 300
|
||||
clockSkewSeconds = 300
|
||||
|
||||
[KeyVault]
|
||||
aadAppId = ${PCS_AAD_APPID}
|
||||
aadAppSecret = ${PCS_AAD_APPSECRET}
|
||||
name = ${PCS_KEYVAULT_NAME}
|
||||
|
||||
; For more information about ASP.NET logging see
|
||||
; https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging
|
||||
|
@ -58,7 +60,7 @@ clock_skew_seconds = 300
|
|||
; internal logs generated by ASP.NET
|
||||
; ASP.NET log levels: Trace, Debug, Information, Warning, Error, Critical
|
||||
[Logging]
|
||||
IncludeScopes = true
|
||||
includeScopes = true
|
||||
LogLevel:Default = "Warning"
|
||||
LogLevel:System = "Warning"
|
||||
LogLevel:Microsoft = "Warning"
|
||||
|
|
|
@ -13,11 +13,9 @@ run_container() {
|
|||
|
||||
echo "Starting IoT Hub Manager ..."
|
||||
docker run -it -p 9002:9002 \
|
||||
-e PCS_IOTHUB_CONNSTRING \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
|
||||
-e PCS_AUTH_WEBSERVICE_URL \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
"$DOCKER_IMAGE:testing"
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,9 @@ IF %ERRORLEVEL% NEQ 0 GOTO FAIL
|
|||
:: Start the application
|
||||
echo Starting IoT Hub Manager ...
|
||||
docker run -it -p 9002:9002 ^
|
||||
-e PCS_IOTHUB_CONNSTRING ^
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
|
||||
-e PCS_AUTH_WEBSERVICE_URL ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
%DOCKER_IMAGE%:testing
|
||||
|
||||
:: - - - - - - - - - - - - - -
|
||||
|
|
|
@ -1,38 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# Before checking all the env vars, detect whether secrets, usually encrypted, are available or not.
|
||||
# Secrets are not available when building a pull request, so the script will not check for those.
|
||||
detect_secrets() {
|
||||
SECRETS_AVAILABLE="true"
|
||||
if [[ "$TRAVIS_PULL_REQUEST" != "" && "$TRAVIS_PULL_REQUEST" != "false" ]]; then
|
||||
SECRETS_AVAILABLE="false"
|
||||
echo "Warning: secrets and encrypted variables are not available when testing pull requests."
|
||||
fi
|
||||
}
|
||||
|
||||
detect_secrets
|
||||
|
||||
if [[ -z "$PCS_IOTHUB_CONNSTRING" && "$SECRETS_AVAILABLE" = "true" ]]; then
|
||||
echo "Error: the PCS_IOTHUB_CONNSTRING environment variable is not defined."
|
||||
exit -1
|
||||
if [[ -z "$PCS_KEYVAULT_NAME" ]]; then
|
||||
echo "Error: the PCS_KEYVAULT_NAME environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_STORAGEADAPTER_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_STORAGEADAPTER_WEBSERVICE_URL environment variable is not defined."
|
||||
exit -1
|
||||
if [[ -z "$PCS_AAD_APPID" ]]; then
|
||||
echo "Error: the PCS_AAD_APPID environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AUTH_WEBSERVICE_URL" ]]; then
|
||||
echo "Error: the PCS_AUTH_WEBSERVICE_URL environment variable is not defined."
|
||||
exit -1
|
||||
if [[ -z "$PCS_AAD_APPSECRET" ]]; then
|
||||
echo "Error: the PCS_AAD_APPSECRET environment variable is not defined."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AUTH_ISSUER" ]]; then
|
||||
echo "Error: the PCS_AUTH_ISSUER environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [[ -z "$PCS_AUTH_AUDIENCE" ]]; then
|
||||
echo "Error: the PCS_AUTH_AUDIENCE environment variable is not defined."
|
||||
exit -1
|
||||
fi
|
|
@ -1,28 +1,19 @@
|
|||
@ECHO off
|
||||
setlocal enableextensions enabledelayedexpansion
|
||||
:: Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
IF "%PCS_IOTHUB_CONNSTRING%" == "" (
|
||||
echo Error: the PCS_IOTHUB_CONNSTRING environment variable is not defined.
|
||||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
IF "%PCS_KEYVAULT_NAME%" == "" (
|
||||
echo Error: the PCS_KEYVAULT_NAME environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_STORAGEADAPTER_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_STORAGEADAPTER_WEBSERVICE_URL environment variable is not defined.
|
||||
IF "%PCS_AAD_APPID%" == "" (
|
||||
echo Error: the PCS_AAD_APPID environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AUTH_WEBSERVICE_URL%" == "" (
|
||||
echo Error: the PCS_AUTH_WEBSERVICE_URL environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AUTH_ISSUER%" == "" (
|
||||
echo Error: the PCS_AUTH_ISSUER environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
IF "%PCS_AUTH_AUDIENCE%" == "" (
|
||||
echo Error: the PCS_AUTH_AUDIENCE environment variable is not defined.
|
||||
IF "%PCS_AAD_APPSECRET%" == "" (
|
||||
echo Error: the PCS_AAD_APPSECRET environment variable is not defined.
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Prepare the environment variables used by the application.
|
||||
#
|
||||
# For more information about finding IoT Hub settings, more information here:
|
||||
#
|
||||
# * https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-create-through-portal#endpoints
|
||||
# * https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-getstarted
|
||||
#
|
||||
|
||||
# see: Shared access policies => key name => Connection string
|
||||
export PCS_IOTHUB_CONNSTRING="..."
|
||||
|
||||
# The URL where Storage Adapter web service is listening
|
||||
export PCS_STORAGEADAPTER_WEBSERVICE_URL="http://127.0.0.1:9022/v1"
|
||||
|
||||
# The URL where Authentication web service is listening
|
||||
export PCS_AUTH_WEBSERVICE_URL="http://127.0.0.1:9001/v1"
|
||||
|
||||
# The OpenId tokens issuer URL, e.g. https://sts.windows.net/12000000-3400-5600-0000-780000000000/
|
||||
export PCS_AUTH_ISSUER="{enter the token issuer URL here}"
|
||||
|
||||
# The intended audience of the tokens, e.g. your Client Id
|
||||
export PCS_AUTH_AUDIENCE="{enter the tokens audience here}"
|
|
@ -1,22 +0,0 @@
|
|||
:: Prepare the environment variables used by the application.
|
||||
::
|
||||
:: For more information about finding IoT Hub settings, more information here:
|
||||
::
|
||||
:: * https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-create-through-portal#endpoints
|
||||
:: * https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-getstarted
|
||||
::
|
||||
|
||||
:: see: Shared access policies => key name => Connection string
|
||||
SETX PCS_IOTHUB_CONNSTRING "..."
|
||||
|
||||
:: Endpoint to reach the storage adapter
|
||||
SETX PCS_STORAGEADAPTER_WEBSERVICE_URL "http://127.0.0.1:9022/v1"
|
||||
|
||||
:: Endpoint to reach the authentication service
|
||||
SETX PCS_AUTH_WEBSERVICE_URL "http://127.0.0.1:9001/v1"
|
||||
|
||||
:: The OpenId tokens issuer URL, e.g. https://sts.windows.net/12000000-3400-5600-0000-780000000000/
|
||||
SETX PCS_AUTH_ISSUER "{enter the token issuer URL here}"
|
||||
|
||||
:: The intended audience of the tokens, e.g. your Client Id
|
||||
SETX PCS_AUTH_AUDIENCE "{enter the tokens audience here}"
|
|
@ -64,11 +64,9 @@ run_in_sandbox() {
|
|||
|
||||
docker run -it \
|
||||
-p 9002:9002 \
|
||||
-e PCS_IOTHUB_CONNSTRING \
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL \
|
||||
-e PCS_AUTH_WEBSERVICE_URL \
|
||||
-e PCS_AUTH_ISSUER \
|
||||
-e PCS_AUTH_AUDIENCE \
|
||||
-e PCS_KEYVAULT_NAME \
|
||||
-e PCS_AAD_APPID \
|
||||
-e PCS_AAD_APPSECRET \
|
||||
-v "$PCS_CACHE/sandbox/.config:/root/.config" \
|
||||
-v "$PCS_CACHE/sandbox/.dotnet:/root/.dotnet" \
|
||||
-v "$PCS_CACHE/sandbox/.nuget:/root/.nuget" \
|
||||
|
|
|
@ -61,11 +61,9 @@ IF "%1"=="--in-sandbox" GOTO :RunInSandbox
|
|||
:: Start the sandbox and run the application
|
||||
docker run -it ^
|
||||
-p 9002:9002 ^
|
||||
-e PCS_IOTHUB_CONNSTRING ^
|
||||
-e PCS_STORAGEADAPTER_WEBSERVICE_URL ^
|
||||
-e PCS_AUTH_WEBSERVICE_URL ^
|
||||
-e PCS_AUTH_ISSUER ^
|
||||
-e PCS_AUTH_AUDIENCE ^
|
||||
-e PCS_KEYVAULT_NAME ^
|
||||
-e PCS_AAD_APPID ^
|
||||
-e PCS_AAD_APPSECRET ^
|
||||
-v %PCS_CACHE%\sandbox\.config:/root/.config ^
|
||||
-v %PCS_CACHE%\sandbox\.dotnet:/root/.dotnet ^
|
||||
-v %PCS_CACHE%\sandbox\.nuget:/root/.nuget ^
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Example usage (see "travis help" for more information):
|
||||
# travis help
|
||||
# travis login --pro
|
||||
# travis whoami --pro
|
||||
# travis accounts --pro
|
||||
# travis history
|
||||
# travis monitor --pro
|
||||
# travis settings
|
||||
# travis show
|
||||
# travis status
|
||||
# travis token --pro
|
||||
# travis whatsup --pro
|
||||
|
||||
set -e
|
||||
APP_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )/"
|
||||
cd $APP_HOME
|
||||
|
||||
mkdir -p .travis
|
||||
|
||||
docker run -it \
|
||||
-v $APP_HOME/.travis:/root/.travis \
|
||||
-v $APP_HOME:/opt/code \
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh $*
|
||||
|
||||
set +e
|
|
@ -1,28 +0,0 @@
|
|||
@ECHO off & setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
:: Example usage (see "travis help" for more information:
|
||||
:: travis help
|
||||
:: travis login --pro
|
||||
:: travis whoami --pro
|
||||
:: travis accounts --pro
|
||||
:: travis history
|
||||
:: travis monitor --pro
|
||||
:: travis settings
|
||||
:: travis show
|
||||
:: travis status
|
||||
:: travis token --pro
|
||||
:: travis whatsup --pro
|
||||
|
||||
:: strlen("\scripts\") => 9
|
||||
SET APP_HOME=%~dp0
|
||||
SET APP_HOME=%APP_HOME:~0,-9%
|
||||
cd %APP_HOME%
|
||||
|
||||
mkdir .travis 2>NUL
|
||||
|
||||
docker run -it ^
|
||||
-v %APP_HOME%\.travis:/root/.travis ^
|
||||
-v %APP_HOME%:/opt/code ^
|
||||
azureiotpcs/travis-cli:1.8.8 /root/bin/travis.sh %*
|
||||
|
||||
endlocal
|
|
@ -14,10 +14,10 @@ spec:
|
|||
servicePort: 10080
|
||||
tls:
|
||||
- hosts:
|
||||
- DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||
- DNSGIVENNAME.REGION.southeastasia.cloudapp.azure.com
|
||||
secretName: tls-secret
|
||||
rules:
|
||||
- host: DNSGIVENNAME.REGION.cloudapp.azure.com
|
||||
- host: DNSGIVENNAME.REGION.southeastasia.cloudapp.azure.com
|
||||
http:
|
||||
paths:
|
||||
- path: /storageadapter/(.*)
|
||||
|
|
|
@ -46,15 +46,9 @@ services:
|
|||
auth:
|
||||
image: azureiotpcs/pcs-auth-dotnet:testing
|
||||
environment:
|
||||
- PCS_AUTH_ISSUER
|
||||
- PCS_AUTH_AUDIENCE
|
||||
- PCS_AUTH_REQUIRED
|
||||
- PCS_AAD_ENDPOINT_URL
|
||||
- PCS_AAD_TENANT
|
||||
- PCS_KEYVAULT_NAME
|
||||
- PCS_AAD_APPID
|
||||
- PCS_AAD_APPSECRET
|
||||
- PCS_ARM_ENDPOINT_URL
|
||||
- PCS_CORS_WHITELIST
|
||||
- PCS_APPLICATION_SECRET
|
||||
|
||||
iothubmanager:
|
||||
image: azureiotpcs/iothub-manager-dotnet:testing
|
||||
|
@ -62,27 +56,18 @@ services:
|
|||
- auth
|
||||
- storageadapter
|
||||
environment:
|
||||
- PCS_AUTH_WEBSERVICE_URL=http://auth:9001/v1
|
||||
- PCS_IOTHUB_CONNSTRING
|
||||
- PCS_STORAGEADAPTER_WEBSERVICE_URL=http://storageadapter:9022/v1
|
||||
- PCS_AUTH_ISSUER
|
||||
- PCS_AUTH_AUDIENCE
|
||||
- PCS_AUTH_REQUIRED
|
||||
- PCS_CORS_WHITELIST
|
||||
- PCS_APPLICATION_SECRET
|
||||
- PCS_KEYVAULT_NAME
|
||||
- PCS_AAD_APPID
|
||||
- PCS_AAD_APPSECRET
|
||||
|
||||
devicesimulation:
|
||||
image: azureiotpcs/device-simulation-dotnet:DS-1.0.3
|
||||
depends_on:
|
||||
- storageadapter
|
||||
environment:
|
||||
- PCS_IOTHUB_CONNSTRING
|
||||
- PCS_STORAGEADAPTER_WEBSERVICE_URL=http://storageadapter:9022/v1
|
||||
- PCS_AUTH_ISSUER
|
||||
- PCS_AUTH_AUDIENCE
|
||||
- PCS_AUTH_REQUIRED
|
||||
- PCS_CORS_WHITELIST
|
||||
- PCS_APPLICATION_SECRET
|
||||
- PCS_KEYVAULT_NAME
|
||||
- PCS_AAD_APPID
|
||||
- PCS_AAD_APPSECRET
|
||||
# How one could mount custom device models
|
||||
# NOTE: Volumes disabled for local development
|
||||
# volumes:
|
||||
|
@ -94,25 +79,9 @@ services:
|
|||
- auth
|
||||
- storageadapter
|
||||
environment:
|
||||
- PCS_STORAGEADAPTER_WEBSERVICE_URL=http://storageadapter:9022/v1
|
||||
- PCS_AUTH_WEBSERVICE_URL=http://auth:9001/v1
|
||||
- PCS_DIAGNOSTICS_WEBSERVICE_URL=http://diagnostics:9006/v1
|
||||
- PCS_TELEMETRY_DOCUMENTDB_CONNSTRING
|
||||
- PCS_AUTH_ISSUER
|
||||
- PCS_AUTH_AUDIENCE
|
||||
- PCS_AUTH_REQUIRED
|
||||
- PCS_CORS_WHITELIST
|
||||
- PCS_APPLICATION_SECRET
|
||||
- PCS_AAD_TENANT
|
||||
- PCS_KEYVAULT_NAME
|
||||
- PCS_AAD_APPID
|
||||
- PCS_AAD_APPSECRET
|
||||
- PCS_TELEMETRY_STORAGE_TYPE
|
||||
- PCS_TSI_FQDN
|
||||
- PCS_AZUREBLOB_CONNSTRING
|
||||
- PCS_ACTION_EVENTHUB_CONNSTRING
|
||||
- PCS_ACTION_EVENTHUB_NAME
|
||||
- PCS_LOGICAPP_ENDPOINT_URL
|
||||
- PCS_SOLUTION_WEBSITE_URL
|
||||
|
||||
config:
|
||||
image: azureiotpcs/pcs-config-dotnet:testing
|
||||
|
@ -122,32 +91,16 @@ services:
|
|||
- devicesimulation
|
||||
- telemetry
|
||||
environment:
|
||||
- PCS_AUTH_WEBSERVICE_URL=http://auth:9001/v1
|
||||
- PCS_STORAGEADAPTER_WEBSERVICE_URL=http://storageadapter:9022/v1
|
||||
- PCS_DEVICESIMULATION_WEBSERVICE_URL=http://devicesimulation:9003/v1
|
||||
- PCS_TELEMETRY_WEBSERVICE_URL=http://telemetry:9004/v1
|
||||
- PCS_SOLUTION_TYPE
|
||||
- PCS_AZUREMAPS_KEY
|
||||
- PCS_AUTH_ISSUER
|
||||
- PCS_AUTH_AUDIENCE
|
||||
- PCS_AUTH_REQUIRED
|
||||
- PCS_CORS_WHITELIST
|
||||
- PCS_APPLICATION_SECRET
|
||||
- PCS_SEED_TEMPLATE
|
||||
- PCS_OFFICE365_CONNECTION_URL
|
||||
- PCS_SOLUTION_NAME
|
||||
- PCS_SUBSCRIPTION_ID
|
||||
- PCS_ARM_ENDPOINT_URL
|
||||
- PCS_KEYVAULT_NAME
|
||||
- PCS_AAD_APPID
|
||||
- PCS_AAD_APPSECRET
|
||||
|
||||
storageadapter:
|
||||
image: azureiotpcs/pcs-storage-adapter-dotnet:testing
|
||||
environment:
|
||||
- PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING
|
||||
- PCS_AUTH_ISSUER
|
||||
- PCS_AUTH_AUDIENCE
|
||||
- PCS_AUTH_REQUIRED
|
||||
- PCS_CORS_WHITELIST
|
||||
- PCS_APPLICATION_SECRET
|
||||
- PCS_KEYVAULT_NAME
|
||||
- PCS_AAD_APPID
|
||||
- PCS_AAD_APPSECRET
|
||||
|
||||
asamanager:
|
||||
image: azureiotpcs/asa-manager-dotnet:testing
|
||||
|
@ -156,37 +109,15 @@ services:
|
|||
- iothubmanager
|
||||
- config
|
||||
environment:
|
||||
- PCS_TELEMETRY_DOCUMENTDB_CONNSTRING
|
||||
- PCS_TELEMETRY_WEBSERVICE_URL=http://telemetry:9004/v1
|
||||
- PCS_CONFIG_WEBSERVICE_URL=http://config:9005/v1
|
||||
- PCS_IOTHUBMANAGER_WEBSERVICE_URL=http://iothubmanager:9002/v1
|
||||
- PCS_ASA_DATA_AZUREBLOB_ACCOUNT
|
||||
- PCS_ASA_DATA_AZUREBLOB_KEY
|
||||
- PCS_ASA_DATA_AZUREBLOB_ENDPOINT_SUFFIX
|
||||
- PCS_EVENTHUB_CONNSTRING
|
||||
- PCS_EVENTHUB_NAME
|
||||
- PCS_AUTH_REQUIRED
|
||||
- PCS_CORS_WHITELIST
|
||||
- PCS_AUTH_ISSUER
|
||||
- PCS_AUTH_AUDIENCE
|
||||
- PCS_APPLICATION_SECRET
|
||||
- PCS_TELEMETRY_STORAGE_TYPE
|
||||
- PCS_KEYVAULT_NAME
|
||||
- PCS_AAD_APPID
|
||||
- PCS_AAD_APPSECRET
|
||||
|
||||
diagnostics:
|
||||
image: azureiotpcs/pcs-diagnostics-dotnet:testing
|
||||
depends_on:
|
||||
- config
|
||||
environment:
|
||||
- PCS_LOG_LEVEL
|
||||
- PCS_AUTH_ISSUER
|
||||
- PCS_AUTH_AUDIENCE
|
||||
- PCS_AUTH_REQUIRED
|
||||
- PCS_CORS_WHITELIST
|
||||
- PCS_CLOUD_TYPE
|
||||
- PCS_SUBSCRIPTION_ID
|
||||
- PCS_SOLUTION_TYPE
|
||||
- PCS_SOLUTION_NAME
|
||||
- PCS_DEPLOYMENT_ID
|
||||
- PCS_IOTHUB_NAME
|
||||
- PCS_DIAGNOSTICS_ENDPOINT_URL
|
||||
- PCS_CONFIG_WEBSERVICE_URL=http://config:9005/v1
|
||||
- PCS_KEYVAULT_NAME
|
||||
- PCS_AAD_APPID
|
||||
- PCS_AAD_APPSECRET
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Azure.IoTSolutions.StorageAdapter.Services.Diagnostics;
|
||||
using Microsoft.Azure.IoTSolutions.StorageAdapter.Services.Exceptions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.StorageAdapter.Services.Runtime
|
||||
{
|
||||
public interface IConfigData
|
||||
{
|
||||
string GetString(string key, string defaultValue = "");
|
||||
bool GetBool(string key, bool defaultValue = false);
|
||||
int GetInt(string key, int defaultValue = 0);
|
||||
}
|
||||
|
||||
public class ConfigData : IConfigData
|
||||
{
|
||||
private readonly IConfigurationRoot configuration;
|
||||
private readonly ILogger log;
|
||||
|
||||
// Key Vault
|
||||
private KeyVault keyVault;
|
||||
|
||||
// Constants
|
||||
private const string CLIENT_ID = "KeyVault:aadAppId";
|
||||
private const string CLIENT_SECRET = "KeyVault:aadAppSecret";
|
||||
private const string KEY_VAULT_NAME = "KeyVault:name";
|
||||
|
||||
public ConfigData(ILogger logger)
|
||||
{
|
||||
this.log = logger;
|
||||
|
||||
// More info about configuration at
|
||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true);
|
||||
this.configuration = configurationBuilder.Build();
|
||||
|
||||
// Set up Key Vault
|
||||
this.SetUpKeyVault();
|
||||
}
|
||||
|
||||
public string GetString(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.GetSecrets(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool GetBool(string key, bool defaultValue = false)
|
||||
{
|
||||
var value = this.GetSecrets(key, defaultValue.ToString()).ToLowerInvariant();
|
||||
|
||||
var knownTrue = new HashSet<string> { "true", "t", "yes", "y", "1", "-1" };
|
||||
var knownFalse = new HashSet<string> { "false", "f", "no", "n", "0" };
|
||||
|
||||
if (knownTrue.Contains(value)) return true;
|
||||
if (knownFalse.Contains(value)) return false;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public int GetInt(string key, int defaultValue = 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(this.GetSecrets(key, defaultValue.ToString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidConfigurationException($"Unable to load configuration value for '{key}'", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetUpKeyVault()
|
||||
{
|
||||
var clientId = this.GetEnvironmentVariable(CLIENT_ID, string.Empty);
|
||||
var clientSecret = this.GetEnvironmentVariable(CLIENT_SECRET, string.Empty);
|
||||
var keyVaultName = this.GetEnvironmentVariable(KEY_VAULT_NAME, string.Empty);
|
||||
|
||||
// Initailize key vault
|
||||
this.keyVault = new KeyVault(keyVaultName, clientId, clientSecret, this.log);
|
||||
}
|
||||
|
||||
private string GetSecrets(string key, string defaultValue = "")
|
||||
{
|
||||
string value = string.Empty;
|
||||
|
||||
value = this.GetLocalVariable(key, defaultValue);
|
||||
|
||||
// If secrets are not found locally, search in Key-Vault
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
log.Warn($"Value for secret {key} not found in local env. " +
|
||||
$" Trying to get the secret from KeyVault.", () => { });
|
||||
value = this.keyVault.GetSecret(key);
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
private string GetLocalVariable(string key, string defaultValue = "")
|
||||
{
|
||||
return this.configuration.GetValue(key, defaultValue);
|
||||
}
|
||||
|
||||
public string GetEnvironmentVariable(string key, string defaultValue = "")
|
||||
{
|
||||
var value = this.configuration.GetValue(key, defaultValue);
|
||||
this.ReplaceEnvironmentVariables(ref value, defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void ReplaceEnvironmentVariables(ref string value, string defaultValue = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return;
|
||||
|
||||
this.ProcessMandatoryPlaceholders(ref value);
|
||||
|
||||
this.ProcessOptionalPlaceholders(ref value, out bool notFound);
|
||||
|
||||
if (notFound && string.IsNullOrEmpty(value))
|
||||
{
|
||||
value = defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMandatoryPlaceholders(ref string value)
|
||||
{
|
||||
// Pattern for mandatory replacements: ${VAR_NAME}
|
||||
const string PATTERN = @"\${([a-zA-Z_][a-zA-Z0-9_]*)}";
|
||||
|
||||
// Search
|
||||
var keys = (from Match m in Regex.Matches(value, PATTERN)
|
||||
select m.Groups[1].Value).Distinct().ToArray();
|
||||
|
||||
// Replace
|
||||
foreach (DictionaryEntry x in Environment.GetEnvironmentVariables())
|
||||
{
|
||||
if (keys.Contains(x.Key))
|
||||
{
|
||||
value = value.Replace("${" + x.Key + "}", x.Value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// Non replaced placeholders cause an exception
|
||||
keys = (from Match m in Regex.Matches(value, PATTERN)
|
||||
select m.Groups[1].Value).ToArray();
|
||||
if (keys.Length > 0)
|
||||
{
|
||||
var varsNotFound = keys.Aggregate(", ", (current, k) => current + k);
|
||||
this.log.Error("Environment variables not found", () => new { varsNotFound });
|
||||
throw new InvalidConfigurationException("Environment variables not found: " + varsNotFound);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessOptionalPlaceholders(ref string value, out bool notFound)
|
||||
{
|
||||
notFound = false;
|
||||
|
||||
// Pattern for optional replacements: ${?VAR_NAME}
|
||||
const string PATTERN = @"\${\?([a-zA-Z_][a-zA-Z0-9_]*)}";
|
||||
|
||||
// Search
|
||||
var keys = (from Match m in Regex.Matches(value, PATTERN)
|
||||
select m.Groups[1].Value).Distinct().ToArray();
|
||||
|
||||
// Replace
|
||||
foreach (DictionaryEntry x in Environment.GetEnvironmentVariables())
|
||||
{
|
||||
if (keys.Contains(x.Key))
|
||||
{
|
||||
value = value.Replace("${?" + x.Key + "}", x.Value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// Non replaced placeholders cause an exception
|
||||
keys = (from Match m in Regex.Matches(value, PATTERN)
|
||||
select m.Groups[1].Value).ToArray();
|
||||
if (keys.Length > 0)
|
||||
{
|
||||
// Remove placeholders
|
||||
value = keys.Aggregate(value, (current, k) => current.Replace("${?" + k + "}", string.Empty));
|
||||
|
||||
var varsNotFound = keys.Aggregate(", ", (current, k) => current + k);
|
||||
this.log.Warn("Environment variables not found", () => new { varsNotFound });
|
||||
|
||||
notFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
using Microsoft.Azure.IoTSolutions.StorageAdapter.Services.Diagnostics;
|
||||
using Microsoft.Azure.KeyVault;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.StorageAdapter.Services.Runtime
|
||||
{
|
||||
public class KeyVault
|
||||
{
|
||||
|
||||
// Key Vault details and access
|
||||
private readonly string name;
|
||||
private readonly string clientId;
|
||||
private readonly string clientSecret;
|
||||
private ILogger log;
|
||||
|
||||
// Key Vault Client
|
||||
private readonly KeyVaultClient keyVaultClient;
|
||||
|
||||
// Constants
|
||||
private const string KEY_VAULT_URI = "https://{0}.vault.azure.net/secrets/{1}";
|
||||
|
||||
public KeyVault(
|
||||
string name,
|
||||
string clientId,
|
||||
string clientSecret,
|
||||
ILogger logger)
|
||||
{
|
||||
this.name = name;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.log = logger;
|
||||
this.keyVaultClient = new KeyVaultClient(
|
||||
new KeyVaultClient.AuthenticationCallback(this.GetToken));
|
||||
}
|
||||
|
||||
public string GetSecret(string secretKey)
|
||||
{
|
||||
secretKey = secretKey.Split(':').Last();
|
||||
var uri = string.Format(KEY_VAULT_URI, this.name, secretKey);
|
||||
|
||||
try
|
||||
{
|
||||
return this.keyVaultClient.GetSecretAsync(uri).Result.Value;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.log.Error($"Secret {secretKey} not found in Key Vault.", () => { });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//the method that will be provided to the KeyVaultClient
|
||||
private async Task<string> GetToken(string authority, string resource, string scope)
|
||||
{
|
||||
var authContext = new AuthenticationContext(authority);
|
||||
ClientCredential clientCred = new ClientCredential(this.clientId, this.clientSecret);
|
||||
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
this.log.Debug($"Failed to obtain authentication token from key vault.", () => { });
|
||||
throw new System.InvalidOperationException("Failed to obtain the JWT token");
|
||||
}
|
||||
|
||||
return result.AccessToken;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,5 +8,9 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="1.4.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="Microsoft.Azure.KeyVault" Version="2.0.6" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -49,19 +49,19 @@ namespace Microsoft.Azure.IoTSolutions.StorageAdapter.WebService
|
|||
/// <summary>Setup Custom rules overriding autowired ones.</summary>
|
||||
private static void SetupCustomRules(ContainerBuilder builder)
|
||||
{
|
||||
// Instantiate only one logger
|
||||
// TODO: read log level from configuration
|
||||
var logger = new Logger(Uptime.ProcessId, LogLevel.Debug);
|
||||
builder.RegisterInstance(logger).As<ILogger>().SingleInstance();
|
||||
|
||||
// Make sure the configuration is read only once.
|
||||
var config = new Config(new ConfigData());
|
||||
var config = new Config(new ConfigData(logger));
|
||||
builder.RegisterInstance(config).As<IConfig>().SingleInstance();
|
||||
|
||||
// Service configuration is generated by the entry point, so we
|
||||
// prepare the instance here.
|
||||
builder.RegisterInstance(config.ServicesConfig).As<IServicesConfig>().SingleInstance();
|
||||
|
||||
// Instantiate only one logger
|
||||
// TODO: read log level from configuration
|
||||
var logger = new Logger(Uptime.ProcessId, LogLevel.Debug);
|
||||
builder.RegisterInstance(logger).As<ILogger>().SingleInstance();
|
||||
|
||||
// By default Autofac uses a request lifetime, creating new objects
|
||||
// for each request, which is good to reduce the risk of memory
|
||||
// leaks, but not so good for the overall performance.
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Azure.IoTSolutions.StorageAdapter.Services.Diagnostics;
|
||||
using Microsoft.Azure.IoTSolutions.StorageAdapter.Services.Runtime;
|
||||
using Microsoft.Azure.IoTSolutions.StorageAdapter.WebService.Runtime;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.StorageAdapter.WebService
|
||||
|
@ -11,7 +13,7 @@ namespace Microsoft.Azure.IoTSolutions.StorageAdapter.WebService
|
|||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var config = new Config(new ConfigData());
|
||||
var config = new Config(new ConfigData(new Logger(Uptime.ProcessId, LogLevel.Info)));
|
||||
|
||||
/*
|
||||
Print some information to help development and debugging, like
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:9022/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"WebService": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:9022/v1/status",
|
||||
"environmentVariables": {
|
||||
"PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING": "$(PCS_STORAGEADAPTER_DOCUMENTDB_CONNSTRING)"
|
||||
},
|
||||
"applicationUrl": "http://localhost:9022/v1/status"
|
||||
}
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:9022/",
|
||||
"sslPort": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"WebService": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:9022/v1/status",
|
||||
"environmentVariables": {
|
||||
"PCS_KEYVAULT_NAME": "",
|
||||
"PCS_AAD_APPID": "",
|
||||
"PCS_AAD_APPSECRET": ""
|
||||
},
|
||||
"applicationUrl": "http://localhost:9022/v1/status"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,12 +18,12 @@ namespace Microsoft.Azure.IoTSolutions.StorageAdapter.WebService.Runtime
|
|||
public class Config : IConfig
|
||||
{
|
||||
private const string APPLICATION_KEY = "StorageAdapter:";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservice_port";
|
||||
private const string PORT_KEY = APPLICATION_KEY + "webservicePort";
|
||||
private const string STORAGE_TYPE_KEY = APPLICATION_KEY + "storageType";
|
||||
private const string DOCUMENT_DB_CONNECTION_STRING_KEY = APPLICATION_KEY + "documentdb_connstring";
|
||||
private const string DOCUMENT_DB_DATABASE_KEY = APPLICATION_KEY + "documentdb_database";
|
||||
private const string DOCUMENT_DB_COLLECTION_KEY = APPLICATION_KEY + "documentdb_collection";
|
||||
private const string DOCUMENT_DB_RUS_KEY = APPLICATION_KEY + "documentdb_RUs";
|
||||
private const string DOCUMENT_DB_CONNECTION_STRING_KEY = APPLICATION_KEY + "documentDBConnectionString";
|
||||
private const string DOCUMENT_DB_DATABASE_KEY = APPLICATION_KEY + "documentDBdatabase";
|
||||
private const string DOCUMENT_DB_COLLECTION_KEY = APPLICATION_KEY + "documentDBcollection";
|
||||
private const string DOCUMENT_DB_RUS_KEY = APPLICATION_KEY + "documentDBRUs";
|
||||
|
||||
/// <summary>Web service listening port</summary>
|
||||
public int Port { get; }
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Azure.IoTSolutions.StorageAdapter.Services.Exceptions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Microsoft.Azure.IoTSolutions.StorageAdapter.WebService.Runtime
|
||||
{
|
||||
public interface IConfigData
|
||||
{
|
||||
string GetString(string key);
|
||||
int GetInt(string key);
|
||||
}
|
||||
|
||||
public class ConfigData : IConfigData
|
||||
{
|
||||
private readonly IConfigurationRoot configuration;
|
||||
|
||||
public ConfigData()
|
||||
{
|
||||
// More info about configuration at
|
||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration
|
||||
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true);
|
||||
|
||||
this.configuration = configurationBuilder.Build();
|
||||
}
|
||||
|
||||
public string GetString(string key)
|
||||
{
|
||||
var value = this.configuration.GetValue<string>(key);
|
||||
return ReplaceEnvironmentVariables(value);
|
||||
}
|
||||
|
||||
public int GetInt(string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(this.GetString(key));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidConfigurationException($"Unable to load configuration value for '{key}'", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ReplaceEnvironmentVariables(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return value;
|
||||
|
||||
// Extract the name of all the substitutions required
|
||||
// using the following pattern, e.g. ${VAR_NAME}
|
||||
const string pattern = @"\${(?'key'[a-zA-Z_][a-zA-Z0-9_]*)}";
|
||||
var keys = (from Match m
|
||||
in Regex.Matches(value, pattern)
|
||||
select m.Groups[1].Value).ToArray();
|
||||
|
||||
foreach (DictionaryEntry x in Environment.GetEnvironmentVariables())
|
||||
{
|
||||
if (keys.Contains(x.Key))
|
||||
{
|
||||
value = value.Replace("${" + x.Key + "}", x.Value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче