public async Task Configure(string connectionString, string image, string hostname) { Console.WriteLine($"Setting up iotedged with agent image '{image}'"); const string YamlPath = "/etc/iotedge/config.yaml"; Task <string> text = File.ReadAllTextAsync(YamlPath); var doc = new YamlDocument(await text); doc.Replace("provisioning.device_connection_string", connectionString); doc.Replace("agent.config.image", image); doc.Replace("hostname", hostname); foreach (RegistryCredentials c in this.credentials) { doc.Replace("agent.config.auth.serveraddress", c.Address); doc.Replace("agent.config.auth.username", c.User); doc.Replace("agent.config.auth.password", c.Password); } if (this.httpUris.HasValue) { HttpUris uris = this.httpUris.OrDefault(); doc.Replace("connect.management_uri", uris.ConnectManagement); doc.Replace("connect.workload_uri", uris.ConnectWorkload); doc.Replace("listen.management_uri", uris.ListenManagement); doc.Replace("listen.workload_uri", uris.ListenWorkload); } else { doc.Replace("connect.management_uri", "unix:///var/run/iotedge/mgmt.sock"); doc.Replace("connect.workload_uri", "unix:///var/run/iotedge/workload.sock"); doc.Replace("listen.management_uri", "fd://iotedge.mgmt.socket"); doc.Replace("listen.workload_uri", "fd://iotedge.socket"); } string result = doc.ToString(); FileAttributes attr = 0; if (File.Exists(YamlPath)) { attr = File.GetAttributes(YamlPath); File.SetAttributes(YamlPath, attr & ~FileAttributes.ReadOnly); } await File.WriteAllTextAsync(YamlPath, result); if (attr != 0) { File.SetAttributes(YamlPath, attr); } }
public async Task Configure( DeviceProvisioningMethod method, Option <string> agentImage, string hostname, Option <string> parentHostname, string deviceCaCert, string deviceCaPk, string deviceCaCerts, LogLevel runtimeLogLevel) { agentImage.ForEach( image => { Console.WriteLine($"Setting up aziot-edged with agent image {image}"); }, () => { Console.WriteLine("Setting up aziot-edged with agent image 1.0"); }); const string KEYD = "/etc/aziot/keyd/config.toml"; const string CERTD = "/etc/aziot/certd/config.toml"; const string IDENTITYD = "/etc/aziot/identityd/config.toml"; const string EDGED = "/etc/aziot/edged/config.yaml"; // Initialize each service's config file. // The mapped values are: // - Path to the config file (/etc/aziot/[service_name]/config.[toml | yaml]) // - User owning the config file // - Template used to generate the config file. Dictionary <string, (string owner, IConfigDocument document)> config = new Dictionary <string, (string, IConfigDocument)>(); config.Add(KEYD, ("aziotks", InitDocument(KEYD + ".default", true))); config.Add(CERTD, ("aziotcs", InitDocument(CERTD + ".default", true))); config.Add(IDENTITYD, ("aziotid", InitDocument(IDENTITYD + ".default", true))); config.Add(EDGED, ("iotedge", InitDocument(EDGED + ".template", false))); // Directory for storing keys; create it if it doesn't exist. string keyDir = "/var/secrets/aziot/keyd/"; Directory.CreateDirectory(keyDir); SetOwner(keyDir, config[KEYD].owner, "700"); // Need to always reprovision so previous test runs don't affect this one. config[IDENTITYD].document.RemoveIfExists("provisioning"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.always_reprovision_on_startup", true); method.ManualConnectionString.Match( cs => { string keyPath = Path.Combine(keyDir, "device-id"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.source", "manual"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.authentication.method", "sas"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.authentication.device_id_pk", "device-id"); config[KEYD].document.ReplaceOrAdd("preloaded_keys.device-id", $"file://{keyPath}"); string[] segments = cs.Split(";"); foreach (string s in segments) { string[] param = s.Split("=", 2); switch (param[0]) { case "HostName": // replace IoTHub hostname with parent hostname for nested edge config[IDENTITYD].document.ReplaceOrAdd("provisioning.iothub_hostname", parentHostname.GetOrElse(param[1])); break; case "SharedAccessKey": File.WriteAllBytes(keyPath, Convert.FromBase64String(param[1])); SetOwner(keyPath, config[KEYD].owner, "600"); break; case "DeviceId": config[IDENTITYD].document.ReplaceOrAdd("provisioning.device_id", param[1]); break; default: break; } } return(string.Empty); }, () => { config[IDENTITYD].document.RemoveIfExists("provisioning"); return(string.Empty); }); method.Dps.ForEach( dps => { config[IDENTITYD].document.ReplaceOrAdd("provisioning.source", "dps"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.global_endpoint", dps.EndPoint); config[IDENTITYD].document.ReplaceOrAdd("provisioning.scope_id", dps.ScopeId); switch (dps.AttestationType) { case DPSAttestationType.SymmetricKey: string dpsKeyPath = Path.Combine(keyDir, "device-id"); string dpsKey = dps.SymmetricKey.Expect(() => new ArgumentException("Expected symmetric key")); File.WriteAllBytes(dpsKeyPath, Convert.FromBase64String(dpsKey)); SetOwner(dpsKeyPath, config[KEYD].owner, "600"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.method", "symmetric_key"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.symmetric_key", "device-id"); break; case DPSAttestationType.X509: string certPath = dps.DeviceIdentityCertificate.Expect(() => new ArgumentException("Expected path to identity certificate")); string keyPath = dps.DeviceIdentityPrivateKey.Expect(() => new ArgumentException("Expected path to identity private key")); SetOwner(certPath, config[CERTD].owner, "444"); SetOwner(keyPath, config[KEYD].owner, "400"); config[CERTD].document.ReplaceOrAdd("preloaded_certs.device-id", new Uri(certPath).AbsoluteUri); config[KEYD].document.ReplaceOrAdd("preloaded_keys.device-id", new Uri(keyPath).AbsoluteUri); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.method", "x509"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.identity_cert", "device-id"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.identity_pk", "device-id"); break; default: break; } dps.RegistrationId.ForEach(id => { config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.registration_id", id); }); }); agentImage.ForEach(image => { config[EDGED].document.ReplaceOrAdd("agent.config.image", image); }); config[EDGED].document.ReplaceOrAdd("hostname", hostname); config[IDENTITYD].document.ReplaceOrAdd("hostname", hostname); parentHostname.ForEach(v => config[EDGED].document.ReplaceOrAdd("parent_hostname", v)); foreach (RegistryCredentials c in this.credentials) { config[EDGED].document.ReplaceOrAdd("agent.config.auth.serveraddress", c.Address); config[EDGED].document.ReplaceOrAdd("agent.config.auth.username", c.User); config[EDGED].document.ReplaceOrAdd("agent.config.auth.password", c.Password); } config[EDGED].document.ReplaceOrAdd("agent.env.RuntimeLogLevel", runtimeLogLevel.ToString()); if (this.httpUris.HasValue) { HttpUris uris = this.httpUris.OrDefault(); config[EDGED].document.ReplaceOrAdd("connect.management_uri", uris.ConnectManagement); config[EDGED].document.ReplaceOrAdd("connect.workload_uri", uris.ConnectWorkload); config[EDGED].document.ReplaceOrAdd("listen.management_uri", uris.ListenManagement); config[EDGED].document.ReplaceOrAdd("listen.workload_uri", uris.ListenWorkload); } else { UriSocks socks = this.uriSocks; config[EDGED].document.ReplaceOrAdd("connect.management_uri", socks.ConnectManagement); config[EDGED].document.ReplaceOrAdd("connect.workload_uri", socks.ConnectWorkload); config[EDGED].document.ReplaceOrAdd("listen.management_uri", socks.ListenManagement); config[EDGED].document.ReplaceOrAdd("listen.workload_uri", socks.ListenWorkload); } // Clear any existing Identity Service principals. string principalsPath = "/etc/aziot/identityd/config.d"; config[IDENTITYD].document.RemoveIfExists("principal"); if (Directory.Exists(principalsPath)) { Directory.Delete(principalsPath, true); } Directory.CreateDirectory(principalsPath); SetOwner(principalsPath, "aziotid", "755"); // Add the principal entry for aziot-edge to Identity Service. // This is required so aziot-edge can communicate with Identity Service. uint iotedgeUid = await GetIotedgeUid(); AddPrincipal("aziot-edge", iotedgeUid); foreach (string file in new string[] { deviceCaCert, deviceCaPk, deviceCaCerts }) { if (string.IsNullOrEmpty(file)) { throw new ArgumentException("device_ca_cert, device_ca_pk, and trusted_ca_certs must all be provided."); } if (!File.Exists(file)) { throw new ArgumentException($"{file} does not exist."); } } // Files must be readable by KS and CS users. SetOwner(deviceCaCerts, config[CERTD].owner, "444"); SetOwner(deviceCaCert, config[CERTD].owner, "444"); SetOwner(deviceCaPk, config[KEYD].owner, "400"); config[CERTD].document.ReplaceOrAdd("preloaded_certs.aziot-edged-trust-bundle", new Uri(deviceCaCerts).AbsoluteUri); config[CERTD].document.ReplaceOrAdd("preloaded_certs.aziot-edged-ca", new Uri(deviceCaCert).AbsoluteUri); config[KEYD].document.ReplaceOrAdd("preloaded_keys.aziot-edged-ca", new Uri(deviceCaPk).AbsoluteUri); this.proxy.ForEach(proxy => config[EDGED].document.ReplaceOrAdd("agent.env.https_proxy", proxy)); this.upstreamProtocol.ForEach(upstreamProtocol => config[EDGED].document.ReplaceOrAdd("agent.env.UpstreamProtocol", upstreamProtocol.ToString())); foreach (KeyValuePair <string, (string owner, IConfigDocument document)> service in config) { string path = service.Key; string text = service.Value.document.ToString(); await File.WriteAllTextAsync(path, text); SetOwner(path, service.Value.owner, "644"); Console.WriteLine($"Created config {path}"); } }
public async Task Configure(DeviceProvisioningMethod method, Option <string> agentImage, string hostname, string deviceCaCert, string deviceCaPk, string deviceCaCerts, LogLevel runtimeLogLevel) { agentImage.ForEach( image => { Console.WriteLine($"Setting up iotedged with agent image {image}"); }, () => { Console.WriteLine("Setting up iotedged with agent image 1.0"); }); const string YamlPath = "/etc/iotedge/config.yaml"; Task <string> text = File.ReadAllTextAsync(YamlPath); var doc = new YamlDocument(await text); method.ManualConnectionString.Match( cs => { doc.ReplaceOrAdd("provisioning.device_connection_string", cs); return(string.Empty); }, () => { doc.Remove("provisioning.device_connection_string"); return(string.Empty); }); method.Dps.ForEach( dps => { doc.ReplaceOrAdd("provisioning.source", "dps"); doc.ReplaceOrAdd("provisioning.global_endpoint", dps.EndPoint); doc.ReplaceOrAdd("provisioning.scope_id", dps.ScopeId); switch (dps.AttestationType) { case DPSAttestationType.SymmetricKey: doc.ReplaceOrAdd("provisioning.attestation.method", "symmetric_key"); doc.ReplaceOrAdd("provisioning.attestation.symmetric_key", dps.SymmetricKey.Expect(() => new ArgumentException("Expected symmetric key"))); break; case DPSAttestationType.X509: var certUri = new Uri(dps.DeviceIdentityCertificate.Expect(() => new ArgumentException("Expected path to identity certificate"))); var keyUri = new Uri(dps.DeviceIdentityPrivateKey.Expect(() => new ArgumentException("Expected path to identity private key"))); doc.ReplaceOrAdd("provisioning.attestation.method", "x509"); doc.ReplaceOrAdd("provisioning.attestation.identity_cert", certUri.AbsoluteUri); doc.ReplaceOrAdd("provisioning.attestation.identity_pk", keyUri.AbsoluteUri); break; default: doc.ReplaceOrAdd("provisioning.attestation.method", "tpm"); break; } dps.RegistrationId.ForEach(id => { doc.ReplaceOrAdd("provisioning.attestation.registration_id", id); }); }); agentImage.ForEach(image => { doc.ReplaceOrAdd("agent.config.image", image); }); doc.ReplaceOrAdd("hostname", hostname); foreach (RegistryCredentials c in this.credentials) { doc.ReplaceOrAdd("agent.config.auth.serveraddress", c.Address); doc.ReplaceOrAdd("agent.config.auth.username", c.User); doc.ReplaceOrAdd("agent.config.auth.password", c.Password); } doc.ReplaceOrAdd("agent.env.RuntimeLogLevel", runtimeLogLevel.ToString()); if (this.httpUris.HasValue) { HttpUris uris = this.httpUris.OrDefault(); doc.ReplaceOrAdd("connect.management_uri", uris.ConnectManagement); doc.ReplaceOrAdd("connect.workload_uri", uris.ConnectWorkload); doc.ReplaceOrAdd("listen.management_uri", uris.ListenManagement); doc.ReplaceOrAdd("listen.workload_uri", uris.ListenWorkload); } else { doc.ReplaceOrAdd("connect.management_uri", "unix:///var/run/iotedge/mgmt.sock"); doc.ReplaceOrAdd("connect.workload_uri", "unix:///var/run/iotedge/workload.sock"); doc.ReplaceOrAdd("listen.management_uri", "fd://iotedge.mgmt.socket"); doc.ReplaceOrAdd("listen.workload_uri", "fd://iotedge.socket"); } if (!string.IsNullOrEmpty(deviceCaCert) && !string.IsNullOrEmpty(deviceCaPk) && !string.IsNullOrEmpty(deviceCaCerts)) { doc.ReplaceOrAdd("certificates.device_ca_cert", deviceCaCert); doc.ReplaceOrAdd("certificates.device_ca_pk", deviceCaPk); doc.ReplaceOrAdd("certificates.trusted_ca_certs", deviceCaCerts); } this.proxy.ForEach(proxy => doc.ReplaceOrAdd("agent.env.https_proxy", proxy)); this.upstreamProtocol.ForEach(upstreamProtocol => doc.ReplaceOrAdd("agent.env.UpstreamProtocol", upstreamProtocol.ToString())); string result = doc.ToString(); FileAttributes attr = 0; if (File.Exists(YamlPath)) { attr = File.GetAttributes(YamlPath); File.SetAttributes(YamlPath, attr & ~FileAttributes.ReadOnly); } await File.WriteAllTextAsync(YamlPath, result); if (attr != 0) { File.SetAttributes(YamlPath, attr); } }
public async Task Configure(string connectionString, string image, string hostname, string deviceCaCert, string deviceCaPk, string deviceCaCerts, LogLevel runtimeLogLevel) { Console.WriteLine($"Setting up iotedged with agent image '{image}'"); const string YamlPath = "/etc/iotedge/config.yaml"; Task <string> text = File.ReadAllTextAsync(YamlPath); var doc = new YamlDocument(await text); doc.ReplaceOrAdd("provisioning.device_connection_string", connectionString); doc.ReplaceOrAdd("agent.config.image", image); doc.ReplaceOrAdd("hostname", hostname); foreach (RegistryCredentials c in this.credentials) { doc.ReplaceOrAdd("agent.config.auth.serveraddress", c.Address); doc.ReplaceOrAdd("agent.config.auth.username", c.User); doc.ReplaceOrAdd("agent.config.auth.password", c.Password); } doc.ReplaceOrAdd("agent.env.RuntimeLogLevel", runtimeLogLevel.ToString()); if (this.httpUris.HasValue) { HttpUris uris = this.httpUris.OrDefault(); doc.ReplaceOrAdd("connect.management_uri", uris.ConnectManagement); doc.ReplaceOrAdd("connect.workload_uri", uris.ConnectWorkload); doc.ReplaceOrAdd("listen.management_uri", uris.ListenManagement); doc.ReplaceOrAdd("listen.workload_uri", uris.ListenWorkload); } else { doc.ReplaceOrAdd("connect.management_uri", "unix:///var/run/iotedge/mgmt.sock"); doc.ReplaceOrAdd("connect.workload_uri", "unix:///var/run/iotedge/workload.sock"); doc.ReplaceOrAdd("listen.management_uri", "fd://iotedge.mgmt.socket"); doc.ReplaceOrAdd("listen.workload_uri", "fd://iotedge.socket"); } if (!string.IsNullOrEmpty(deviceCaCert) && !string.IsNullOrEmpty(deviceCaPk) && !string.IsNullOrEmpty(deviceCaCerts)) { doc.ReplaceOrAdd("certificates.device_ca_cert", deviceCaCert); doc.ReplaceOrAdd("certificates.device_ca_pk", deviceCaPk); doc.ReplaceOrAdd("certificates.trusted_ca_certs", deviceCaCerts); } this.proxy.ForEach(proxy => doc.ReplaceOrAdd("agent.env.https_proxy", proxy)); this.upstreamProtocol.ForEach(upstreamProtocol => doc.ReplaceOrAdd("agent.env.UpstreamProtocol", upstreamProtocol.ToString())); string result = doc.ToString(); FileAttributes attr = 0; if (File.Exists(YamlPath)) { attr = File.GetAttributes(YamlPath); File.SetAttributes(YamlPath, attr & ~FileAttributes.ReadOnly); } await File.WriteAllTextAsync(YamlPath, result); if (attr != 0) { File.SetAttributes(YamlPath, attr); } }
public async Task Configure( DeviceProvisioningMethod method, Option <string> agentImage, string hostname, Option <string> parentHostname, string deviceCaCert, string deviceCaPk, string deviceCaCerts, LogLevel runtimeLogLevel) { agentImage.ForEach( image => { Console.WriteLine($"Setting up aziot-edged with agent image {image}"); }, () => { Console.WriteLine("Setting up aziot-edged with agent image 1.0"); }); // Initialize each service's config file. Dictionary <string, Config> config = new Dictionary <string, Config>(); config.Add(KEYD, await InitConfig(KEYD + ".default", "aziotks")); config.Add(CERTD, await InitConfig(CERTD + ".default", "aziotcs")); config.Add(IDENTITYD, await InitConfig(IDENTITYD + ".default", "aziotid")); config.Add(EDGED, await InitConfig(EDGED + ".default", "iotedge")); // Directory for storing keys; create it if it doesn't exist. string keyDir = "/var/secrets/aziot/keyd/"; Directory.CreateDirectory(keyDir); SetOwner(keyDir, config[KEYD].Owner, "700"); // Need to always reprovision so previous test runs don't affect this one. config[EDGED].Document.ReplaceOrAdd("auto_reprovisioning_mode", "AlwaysOnStartup"); config[IDENTITYD].Document.RemoveIfExists("provisioning"); parentHostname.ForEach( parent_hostame => config[IDENTITYD].Document.ReplaceOrAdd("provisioning.local_gateway_hostname", parent_hostame)); method.ManualConnectionString.Match( cs => { string keyPath = Path.Combine(keyDir, "device-id"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.source", "manual"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.authentication.method", "sas"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.authentication.device_id_pk", "device-id"); config[KEYD].Document.ReplaceOrAdd("preloaded_keys.device-id", $"file://{keyPath}"); string[] segments = cs.Split(";"); foreach (string s in segments) { string[] param = s.Split("=", 2); switch (param[0]) { case "HostName": // replace IoTHub hostname with parent hostname for nested edge config[IDENTITYD].Document.ReplaceOrAdd("provisioning.iothub_hostname", param[1]); break; case "SharedAccessKey": File.WriteAllBytes(keyPath, Convert.FromBase64String(param[1])); SetOwner(keyPath, config[KEYD].Owner, "600"); break; case "DeviceId": config[IDENTITYD].Document.ReplaceOrAdd("provisioning.device_id", param[1]); break; default: break; } } this.SetAuth("device-id", config); return(string.Empty); }, () => { config[IDENTITYD].Document.RemoveIfExists("provisioning"); return(string.Empty); }); method.Dps.ForEach( dps => { config[IDENTITYD].Document.ReplaceOrAdd("provisioning.source", "dps"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.global_endpoint", dps.EndPoint); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.scope_id", dps.ScopeId); switch (dps.AttestationType) { case DPSAttestationType.SymmetricKey: string dpsKeyPath = Path.Combine(keyDir, "device-id"); string dpsKey = dps.SymmetricKey.Expect(() => new ArgumentException("Expected symmetric key")); File.WriteAllBytes(dpsKeyPath, Convert.FromBase64String(dpsKey)); SetOwner(dpsKeyPath, config[KEYD].Owner, "600"); config[KEYD].Document.ReplaceOrAdd("preloaded_keys.device-id", new Uri(dpsKeyPath).AbsoluteUri); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.method", "symmetric_key"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.symmetric_key", "device-id"); this.SetAuth("device-id", config); break; case DPSAttestationType.X509: string certPath = dps.DeviceIdentityCertificate.Expect(() => new ArgumentException("Expected path to identity certificate")); string keyPath = dps.DeviceIdentityPrivateKey.Expect(() => new ArgumentException("Expected path to identity private key")); SetOwner(certPath, config[CERTD].Owner, "444"); SetOwner(keyPath, config[KEYD].Owner, "400"); config[CERTD].Document.ReplaceOrAdd("preloaded_certs.device-id", new Uri(certPath).AbsoluteUri); config[KEYD].Document.ReplaceOrAdd("preloaded_keys.device-id", new Uri(keyPath).AbsoluteUri); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.method", "x509"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.identity_cert", "device-id"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.identity_pk", "device-id"); this.SetAuth("device-id", config); break; default: break; } dps.RegistrationId.ForEach(id => { config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.registration_id", id); }); }); agentImage.ForEach(image => { config[EDGED].Document.ReplaceOrAdd("agent.config.image", image); }); config[EDGED].Document.ReplaceOrAdd("hostname", hostname); config[IDENTITYD].Document.ReplaceOrAdd("hostname", hostname); parentHostname.ForEach(v => config[EDGED].Document.ReplaceOrAdd("parent_hostname", v)); foreach (RegistryCredentials c in this.credentials) { config[EDGED].Document.ReplaceOrAdd("agent.config.auth.serveraddress", c.Address); config[EDGED].Document.ReplaceOrAdd("agent.config.auth.username", c.User); config[EDGED].Document.ReplaceOrAdd("agent.config.auth.password", c.Password); } config[EDGED].Document.ReplaceOrAdd("agent.env.RuntimeLogLevel", runtimeLogLevel.ToString()); if (this.httpUris.HasValue) { HttpUris uris = this.httpUris.OrDefault(); config[EDGED].Document.ReplaceOrAdd("connect.management_uri", uris.ConnectManagement); config[EDGED].Document.ReplaceOrAdd("connect.workload_uri", uris.ConnectWorkload); config[EDGED].Document.ReplaceOrAdd("listen.management_uri", uris.ListenManagement); config[EDGED].Document.ReplaceOrAdd("listen.workload_uri", uris.ListenWorkload); } else { UriSocks socks = this.uriSocks; config[EDGED].Document.ReplaceOrAdd("connect.management_uri", socks.ConnectManagement); config[EDGED].Document.ReplaceOrAdd("connect.workload_uri", socks.ConnectWorkload); config[EDGED].Document.ReplaceOrAdd("listen.management_uri", socks.ListenManagement); config[EDGED].Document.ReplaceOrAdd("listen.workload_uri", socks.ListenWorkload); } foreach (string file in new string[] { deviceCaCert, deviceCaPk, deviceCaCerts }) { if (string.IsNullOrEmpty(file)) { throw new ArgumentException("device_ca_cert, device_ca_pk, and trusted_ca_certs must all be provided."); } if (!File.Exists(file)) { throw new ArgumentException($"{file} does not exist."); } } // Files must be readable by KS and CS users. SetOwner(deviceCaCerts, config[CERTD].Owner, "444"); SetOwner(deviceCaCert, config[CERTD].Owner, "444"); SetOwner(deviceCaPk, config[KEYD].Owner, "400"); config[CERTD].Document.ReplaceOrAdd("preloaded_certs.aziot-edged-trust-bundle", new Uri(deviceCaCerts).AbsoluteUri); config[CERTD].Document.ReplaceOrAdd("preloaded_certs.aziot-edged-ca", new Uri(deviceCaCert).AbsoluteUri); config[KEYD].Document.ReplaceOrAdd("preloaded_keys.aziot-edged-ca", new Uri(deviceCaPk).AbsoluteUri); this.proxy.ForEach(proxy => config[EDGED].Document.ReplaceOrAdd("agent.env.https_proxy", proxy)); this.upstreamProtocol.ForEach(upstreamProtocol => config[EDGED].Document.ReplaceOrAdd("agent.env.UpstreamProtocol", upstreamProtocol.ToString())); foreach (KeyValuePair <string, Config> service in config) { string path = service.Key; string text = service.Value.Document.ToString(); await File.WriteAllTextAsync(path, text); SetOwner(path, service.Value.Owner, "644"); Console.WriteLine($"Created config {path}"); } using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2))) { Console.WriteLine($"Calling iotedge system set-log-level {runtimeLogLevel.ToString().ToLower()}"); string[] output = await Process.RunAsync("iotedge", $"system set-log-level {runtimeLogLevel.ToString().ToLower()}", cts.Token); Console.WriteLine($"{output.ToString()}"); } }