Skip to content

Commit

Permalink
iotedge check improvements for nested edge (#4608)
Browse files Browse the repository at this point in the history
In nested environment, the diagnostic image extracts the trust bundle before establishing the communication with upstream.
Improved error message with a suggestion for our user.

Before it was just trusting the upstream CA.

Removed unused publishing of connectivity test.
Test:
Put a dummy CA inside the trustbundle. Confirmed it fails 
Put good CA, confirmed it passes
Checked in regular, non nested scenario for regression.
  • Loading branch information
huguesBouvier authored Mar 17, 2021
1 parent 51f1102 commit 22819dd
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 16 deletions.
9 changes: 9 additions & 0 deletions Microsoft.Azure.Devices.Edge.sln
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "es6numberserializer", "edge
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ManifestSignerClient", "samples\dotnet\ManifestSignerClient\ManifestSignerClient.csproj", "{C4C3CEB4-1177-4D1C-9BAE-EE0453831905}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IotedgeDiagnosticsDotnet", "edge-modules\iotedge-diagnostics-dotnet\IotedgeDiagnosticsDotnet.csproj", "{59CF2F3B-5FCC-43BE-B221-1E7A956D4792}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CheckInBuild|Any CPU = CheckInBuild|Any CPU
Expand Down Expand Up @@ -662,6 +664,12 @@ Global
{C4C3CEB4-1177-4D1C-9BAE-EE0453831905}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4C3CEB4-1177-4D1C-9BAE-EE0453831905}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4C3CEB4-1177-4D1C-9BAE-EE0453831905}.Release|Any CPU.Build.0 = Release|Any CPU
{59CF2F3B-5FCC-43BE-B221-1E7A956D4792}.CheckInBuild|Any CPU.ActiveCfg = CheckInBuild|Any CPU
{59CF2F3B-5FCC-43BE-B221-1E7A956D4792}.CheckInBuild|Any CPU.Build.0 = CheckInBuild|Any CPU
{59CF2F3B-5FCC-43BE-B221-1E7A956D4792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{59CF2F3B-5FCC-43BE-B221-1E7A956D4792}.Debug|Any CPU.Build.0 = Debug|Any CPU
{59CF2F3B-5FCC-43BE-B221-1E7A956D4792}.Release|Any CPU.ActiveCfg = Release|Any CPU
{59CF2F3B-5FCC-43BE-B221-1E7A956D4792}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -754,6 +762,7 @@ Global
{1915CE7E-E949-4633-9862-D92BD5E873B5} = {66964A75-04AC-4FDE-8505-E6CB2EF90BE8}
{BE39EC1F-7E7C-4421-93BF-1DF02C1E6A15} = {66964A75-04AC-4FDE-8505-E6CB2EF90BE8}
{C4C3CEB4-1177-4D1C-9BAE-EE0453831905} = {A6D8677F-DB76-459E-B6DE-110AFCEF7F08}
{59CF2F3B-5FCC-43BE-B221-1E7A956D4792} = {578D5330-2F72-44C6-9DB5-C93B3F42C473}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D71830F5-3AF5-46B4-8A9E-1DCE4F2253AC}
Expand Down
54 changes: 42 additions & 12 deletions edge-modules/iotedge-diagnostics-dotnet/src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@
namespace Diagnostics
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Configuration;
using ProxyLib.Proxy;

class Program
{
const string CLIENT_WORKLOAD_API_VERSION = "2019-01-30";

public static int Main(string[] args)
{
try
Expand Down Expand Up @@ -40,7 +46,7 @@ static async Task MainAsync(string[] args)
await EdgeAgent(config["management-uri"]);
break;
case "upstream":
await Upstream(config["hostname"], config["port"], config["proxy"], config["isNested"]);
await Upstream(config["hostname"], config["port"], config["proxy"], config["isNested"], config["workload_uri"]);
break;
case "local-time":
Console.WriteLine(DateTime.Now.ToUnixTimestamp());
Expand Down Expand Up @@ -71,33 +77,57 @@ static async Task EdgeAgent(string managementUri)
}
}

static async Task Upstream(string hostname, string port, string proxy, string isNested)
static async Task LoadTrustBundle(string workload_uri)
{
string dummy = "0";

IEnumerable<X509Certificate2> trustBundle = await CertificateHelper.
GetTrustBundleFromEdgelet(new Uri(workload_uri), dummy, CLIENT_WORKLOAD_API_VERSION, dummy, dummy);
CertificateHelper.InstallCertificates(trustBundle, null);
}

static async Task Upstream(string hostname, string port, string proxy, string isNested, string workload_uri)
{
bool nested = string.Equals(isNested, "true");

if (port == "443")
{
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>
{
return true; // Is valid
};

if (proxy != null)
{
Environment.SetEnvironmentVariable("https_proxy", proxy);
}

if (nested)
{
await LoadTrustBundle(workload_uri);
}

var httpClient = new HttpClient(httpClientHandler);
var logsUrl = string.Format("https://{0}/devices/0000/modules", hostname);
var httpRequest = new HttpRequestMessage(HttpMethod.Get, logsUrl);
HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);

if (isNested != null)
try
{
HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);
if (nested)
{
var keys = httpResponseMessage.Headers.GetValues("iothub-errorcode");
if (!keys.Contains("InvalidProtocolVersion"))
{
throw new Exception($"Wrong value for iothub-errorcode header");
}
}
}
catch (Exception ex)
{
var keys = httpResponseMessage.Headers.GetValues("iothub-errorcode");
if (!keys.Contains("InvalidProtocolVersion"))
string message = ex.Message;
if ((ex.InnerException is AuthenticationException) && nested)
{
throw new Exception($"Wrong value for iothub-errorcode header");
message += "Make sure that the parent root certificate is part of this device trustbundle. Use the command 'openssl s_client -connect parent_hostname:443' to display parent certificate chain.";
}

throw new Exception(message);
}
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,10 @@ public static bool ValidateCertExpiry(X509Certificate2 certificate, ILogger logg
public static void InstallCertificates(IEnumerable<X509Certificate2> certificateChain, ILogger logger)
{
X509Certificate2[] certs = Preconditions.CheckNotNull(certificateChain, nameof(certificateChain)).ToArray();
Preconditions.CheckNotNull(logger, nameof(logger));

StoreName storeName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? StoreName.CertificateAuthority : StoreName.Root;

logger.LogInformation($"Installing certificates {string.Join(",", certs.Select(c => $"[{c.Subject}:{c.GetExpirationDateString()}]"))} to {storeName}");
logger?.LogInformation($"Installing certificates {string.Join(",", certs.Select(c => $"[{c.Subject}:{c.GetExpirationDateString()}]"))} to {storeName}");
using (var store = new X509Store(storeName, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadWrite);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ impl ContainerConnectUpstream {

self.upstream_hostname = Some(upstream_hostname.clone());

let workload_uri = settings.connect().workload_uri().to_string();
let workload_uri_path = settings.connect().workload_uri().path().to_string();
let map_volume = format!("{}:{}", workload_uri_path, workload_uri_path);

let network_name = settings.moby_runtime().network().name();
self.network_name = Some(network_name.to_owned());

Expand All @@ -127,6 +131,10 @@ impl ContainerConnectUpstream {
args.extend(&["--network", network_name]);
}

if settings.parent_hostname().is_some() {
args.extend(&["-v", &map_volume]);
}

self.diagnostics_image_name = Some(check.diagnostics_image_name.clone());
args.extend(&[
&diagnostics_image_name,
Expand All @@ -141,6 +149,7 @@ impl ContainerConnectUpstream {

if settings.parent_hostname().is_some() {
args.extend(&["--isNested", "true"]);
args.extend(&["--workload_uri", &workload_uri]);
}

if &port == "443" {
Expand Down
2 changes: 0 additions & 2 deletions scripts/linux/buildBranch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ SRC_E2E_TEST_FILES_DIR=$ROOT_FOLDER/e2e_test_files
SRC_CERT_TOOLS_DIR=$ROOT_FOLDER/tools/CACertificates
FUNCTIONS_SAMPLE_DIR=$ROOT_FOLDER/edge-modules/functions/samples
VERSIONINFO_FILE_PATH=$BUILD_REPOSITORY_LOCALPATH/versionInfo.json
CONNECTIVITY_TEST_SCRIPT_DIR=$ROOT_FOLDER/test/connectivity/scripts
DOTNET_RUNTIME=netcoreapp3.1

usage()
Expand Down Expand Up @@ -254,7 +253,6 @@ publish_files $SRC_SCRIPTS_DIR $PUBLISH_FOLDER
publish_files $SRC_E2E_TEMPLATES_DIR $PUBLISH_FOLDER
publish_files $SRC_E2E_TEST_FILES_DIR $PUBLISH_FOLDER
publish_files $SRC_CERT_TOOLS_DIR $PUBLISH_FOLDER
publish_files $CONNECTIVITY_TEST_SCRIPT_DIR $PUBLISH_FOLDER

publish_quickstart linux-arm
publish_quickstart linux-x64
Expand Down

0 comments on commit 22819dd

Please sign in to comment.