Skip to content

Commit 070610d

Browse files
authored
Remove Subject Alternate Name Sanitization in Workload Cert Creation (#5798)
1. Remove Subject Alternate Name Sanitization of Common Name, this leads to TLS Handshake Errors since the hostname differs from the SAN. 2. Added Unit Test 3. Enable 1ES Agents on CI E2E Tests End-End CI Run : https://msazure.visualstudio.com/One/_build/results?buildId=48717636&view=logs&j=f1061aa8-bee6-5103-5b5c-2b2c91b98c58 ## Azure IoT Edge PR checklist:
1 parent 78d4c21 commit 070610d

File tree

6 files changed

+104
-112
lines changed

6 files changed

+104
-112
lines changed

builds/checkin/e2e-checkin.yaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,6 @@ stages:
5858
builtImages: $[ stageDependencies.PublishManifests.PublishManifest.result ]
5959
builtPackages: $[ stageDependencies.BuildPackages.linux.result ]
6060
steps:
61-
# Since 1ES Agents may have a non-conformed RFC 1035 Host Name, Modify the Host Name here so that Downstream communication doesn't
62-
# have TLS Handshake errors
63-
- bash: |
64-
echo "Writing Host Name e2e-$BUILD_BUILDID"
65-
sudo hostnamectl set-hostname e2e-$BUILD_BUILDID
66-
displayName: Modify Host Name
6761
- template: ../e2e/templates/e2e-setup.yaml
6862
- template: ../e2e/templates/e2e-run.yaml
6963

builds/e2e/e2e.yaml

Lines changed: 55 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -55,101 +55,90 @@ jobs:
5555
- template: templates/e2e-clear-docker-cached-images.yaml
5656
- template: templates/e2e-run.yaml
5757

58-
# Using 1ES-hosted agents in master branch causes test failures; disabling
59-
# until fixed.
60-
# ################################################################################
61-
# - job: ubuntu_1804_msmoby
62-
# ################################################################################
63-
# displayName: Ubuntu 18.04 with iotedge-moby
64-
65-
# pool:
66-
# name: $(pool.linux.name)
67-
# demands:
68-
# - ImageOverride -equals agent-aziotedge-ubuntu-18.04-msmoby
69-
70-
# variables:
71-
# os: linux
72-
# arch: amd64
73-
# artifactName: iotedged-ubuntu18.04-amd64
74-
# identityServiceArtifactName: packages_ubuntu-18.04_amd64
75-
# identityServicePackageFilter: aziot-identity-service_*_amd64.deb
76-
77-
# steps:
78-
# - template: templates/e2e-setup.yaml
79-
# - template: templates/e2e-run.yaml
58+
59+
################################################################################
60+
- job: ubuntu_1804_msmoby
61+
################################################################################
62+
displayName: Ubuntu 18.04 with iotedge-moby
63+
64+
pool:
65+
name: $(pool.linux.name)
66+
demands:
67+
- ImageOverride -equals agent-aziotedge-ubuntu-18.04-msmoby
68+
69+
variables:
70+
os: linux
71+
arch: amd64
72+
artifactName: iotedged-ubuntu18.04-amd64
73+
identityServiceArtifactName: packages_ubuntu-18.04_amd64
74+
identityServicePackageFilter: aziot-identity-service_*_amd64.deb
75+
76+
steps:
77+
- template: templates/e2e-setup.yaml
78+
- template: templates/e2e-run.yaml
8079

8180
################################################################################
8281
- job: ubuntu_1804_docker
8382
################################################################################
84-
# displayName: Ubuntu 18.04 with Docker (minimal)
85-
displayName: Ubuntu 18.04 with Docker
83+
84+
displayName: Ubuntu 18.04 with Docker minimal
8685

8786
pool:
88-
vmImage: ubuntu-18.04
89-
# Using 1ES-hosted agents in master branch causes test failures; disabling
90-
# until fixed.
91-
# name: $(pool.linux.name)
92-
# demands:
93-
# - ImageOverride -equals agent-aziotedge-ubuntu-18.04-docker
87+
name: $(pool.linux.name)
88+
demands:
89+
- ImageOverride -equals agent-aziotedge-ubuntu-18.04-docker
9490

9591
variables:
9692
os: linux
9793
arch: amd64
9894
artifactName: iotedged-ubuntu18.04-amd64
9995
identityServiceArtifactName: packages_ubuntu-18.04_amd64
10096
identityServicePackageFilter: aziot-identity-service_*_amd64.deb
101-
# When we switch to 1ES-hosted agents, we can make this a minimal pipeline
102-
# minimal: true
97+
minimal: true
10398

10499
steps:
105100
- template: templates/e2e-setup.yaml
106101
- template: templates/e2e-run.yaml
107102

108-
# Using 1ES-hosted agents in master branch causes test failures; disabling
109-
# until fixed.
110-
# ################################################################################
111-
# - job: ubuntu_2004_msmoby
112-
# ################################################################################
113-
# displayName: Ubuntu 20.04 with iotedge-moby
114-
115-
# pool:
116-
# name: $(pool.linux.name)
117-
# demands:
118-
# - ImageOverride -equals agent-aziotedge-ubuntu-20.04-msmoby
119-
120-
# variables:
121-
# os: linux
122-
# arch: amd64
123-
# artifactName: iotedged-ubuntu20.04-amd64
124-
# identityServiceArtifactName: packages_ubuntu-20.04_amd64
125-
# identityServicePackageFilter: aziot-identity-service_*_amd64.deb
126-
127-
# steps:
128-
# - template: templates/e2e-setup.yaml
129-
# - template: templates/e2e-run.yaml
103+
104+
################################################################################
105+
- job: ubuntu_2004_msmoby
106+
################################################################################
107+
displayName: Ubuntu 20.04 with iotedge-moby
108+
109+
pool:
110+
name: $(pool.linux.name)
111+
demands:
112+
- ImageOverride -equals agent-aziotedge-ubuntu-20.04-msmoby
113+
114+
variables:
115+
os: linux
116+
arch: amd64
117+
artifactName: iotedged-ubuntu20.04-amd64
118+
identityServiceArtifactName: packages_ubuntu-20.04_amd64
119+
identityServicePackageFilter: aziot-identity-service_*_amd64.deb
120+
121+
steps:
122+
- template: templates/e2e-setup.yaml
123+
- template: templates/e2e-run.yaml
130124

131125
################################################################################
132126
- job: ubuntu_2004_docker
133127
################################################################################
134-
# displayName: Ubuntu 20.04 with Docker (minimal)
135-
displayName: Ubuntu 20.04 with Docker
128+
displayName: Ubuntu 20.04 with Docker minimal
136129

137130
pool:
138-
vmImage: ubuntu-20.04
139-
# Using 1ES-hosted agents in master branch causes test failures; disabling
140-
# until fixed.
141-
# name: $(pool.linux.name)
142-
# demands:
143-
# - ImageOverride -equals agent-aziotedge-ubuntu-20.04-docker
131+
name: $(pool.linux.name)
132+
demands:
133+
- ImageOverride -equals agent-aziotedge-ubuntu-20.04-docker
144134

145135
variables:
146136
os: linux
147137
arch: amd64
148138
artifactName: iotedged-ubuntu20.04-amd64
149139
identityServiceArtifactName: packages_ubuntu-20.04_amd64
150140
identityServicePackageFilter: aziot-identity-service_*_amd64.deb
151-
# When we switch to 1ES-hosted agents, we can make this a minimal pipeline
152-
# minimal: true
141+
minimal: true
153142

154143
steps:
155144
- template: templates/e2e-setup.yaml
@@ -161,17 +150,9 @@ jobs:
161150
displayName: CentOs7 amd64
162151

163152
pool:
164-
name: $(pool.custom.name)
153+
name: $(pool.linux.name)
165154
demands:
166-
- Agent.OS -equals Linux
167-
- Agent.OSArchitecture -equals X64
168-
- run-new-e2e-tests -equals true
169-
- centos -equals 7
170-
# Using 1ES-hosted agents in master branch causes test failures; disabling
171-
# until fixed.
172-
# name: $(pool.linux.name)
173-
# demands:
174-
# - ImageOverride -equals agent-aziotedge-centos-7-msmoby
155+
- ImageOverride -equals agent-aziotedge-centos-7-msmoby
175156

176157
variables:
177158
os: linux

edgelet/edgelet-http-workload/src/module/cert/identity.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ where
7171

7272
let cert_id = format!("aziot-edged/module/{}:identity", &self.module_id);
7373

74-
let module_uri = super::sanitize_dns_name(self.module_uri);
75-
let subject_alt_names = vec![super::SubjectAltName::Dns(module_uri)];
74+
let subject_alt_names = vec![super::SubjectAltName::Dns(self.module_uri)];
7675

7776
let csr_extensions = identity_cert_extensions().map_err(|_| {
7877
edgelet_http::error::server_error("failed to set identity csr extensions")

edgelet/edgelet-http-workload/src/module/cert/mod.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -133,22 +133,6 @@ impl CertApi {
133133
}
134134
}
135135

136-
/// DNS names must conform to following rules per RFC 1035:
137-
/// - Length less than 64 characters
138-
/// - Contains only lowercase alphanumeric characters or '-'
139-
/// - Starts and ends with an alphanumeric character
140-
///
141-
/// This function removes illegal characters from a given DNS name and trims it to 63 characters.
142-
pub fn sanitize_dns_name(name: String) -> String {
143-
name.trim_start_matches(|c: char| !c.is_ascii_alphabetic())
144-
.trim_end_matches(|c: char| !c.is_ascii_alphanumeric())
145-
.to_lowercase()
146-
.chars()
147-
.filter(|c| c.is_ascii_alphanumeric() || c == &'-')
148-
.take(63)
149-
.collect::<String>()
150-
}
151-
152136
fn new_keys() -> Result<
153137
(
154138
openssl::pkey::PKey<openssl::pkey::Private>,

edgelet/edgelet-http-workload/src/module/cert/server.rs

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,11 @@ where
9595
let common_name_san = if std::net::IpAddr::from_str(&common_name_san).is_ok() {
9696
super::SubjectAltName::Ip(common_name_san)
9797
} else {
98-
let common_name_san = super::sanitize_dns_name(common_name_san);
99-
10098
super::SubjectAltName::Dns(common_name_san)
10199
};
102100

103101
// Server certificates have the module ID and certificate CN as the SANs.
104-
let module_id_san = super::sanitize_dns_name(self.module_id);
105-
let module_id_san = super::SubjectAltName::Dns(module_id_san);
102+
let module_id_san = super::SubjectAltName::Dns(self.module_id);
106103

107104
let subject_alt_names = vec![common_name_san, module_id_san];
108105

@@ -133,17 +130,30 @@ fn server_cert_extensions(
133130

134131
#[cfg(test)]
135132
mod tests {
133+
use crate::module::cert::CertificateResponse;
136134
use http_common::server::Route;
137135

138136
use edgelet_test_utils::{test_route_err, test_route_ok};
139137

140138
const TEST_PATH: &str = "/modules/testModule/genid/1/certificate/server";
141139

140+
const MODULE_NAME: &str = "testModule";
141+
142+
async fn post(
143+
route: super::Route<edgelet_test_utils::runtime::Runtime>,
144+
) -> http_common::server::RouteResponse {
145+
let body = super::ServerCertificateRequest {
146+
common_name: MODULE_NAME.to_string(),
147+
};
148+
149+
route.post(Some(body)).await
150+
}
151+
142152
#[test]
143153
fn parse_uri() {
144154
// Valid URI
145155
let route = test_route_ok!(TEST_PATH);
146-
assert_eq!("testModule", &route.module_id);
156+
assert_eq!(MODULE_NAME, &route.module_id);
147157
assert_eq!("1", &route.gen_id);
148158
assert_eq!(nix::unistd::getpid().as_raw(), route.pid);
149159

@@ -162,16 +172,35 @@ mod tests {
162172

163173
#[tokio::test]
164174
async fn auth() {
165-
async fn post(
166-
route: super::Route<edgelet_test_utils::runtime::Runtime>,
167-
) -> http_common::server::RouteResponse {
168-
let body = super::ServerCertificateRequest {
169-
common_name: "testModule".to_string(),
170-
};
171-
172-
route.post(Some(body)).await
175+
edgelet_test_utils::test_auth_caller!(TEST_PATH, MODULE_NAME, post);
176+
}
177+
178+
#[tokio::test]
179+
async fn verifysans() {
180+
let route = edgelet_test_utils::test_route_ok!(TEST_PATH);
181+
{
182+
let pid = nix::unistd::getpid().as_raw();
183+
let mut runtime = route.runtime.lock().await;
184+
runtime.module_auth = std::collections::BTreeMap::new();
185+
runtime
186+
.module_auth
187+
.insert(MODULE_NAME.to_string(), vec![pid]);
173188
}
174189

175-
edgelet_test_utils::test_auth_caller!(TEST_PATH, "testModule", post);
190+
let response = post(route).await.unwrap();
191+
let body_bytes = hyper::body::to_bytes(response.into_body()).await.unwrap();
192+
let cert_response = serde_json::from_str::<CertificateResponse>(
193+
&String::from_utf8(body_bytes.to_vec()).unwrap(),
194+
)
195+
.unwrap()
196+
.certificate;
197+
198+
let cert = openssl::x509::X509::from_pem(cert_response.as_bytes())
199+
.map_err(|_| edgelet_http::error::server_error("failed to parse cert"));
200+
let sans = cert.unwrap().subject_alt_names();
201+
for san in sans.unwrap().iter() {
202+
let name = san.dnsname().unwrap();
203+
assert_eq!(MODULE_NAME.to_lowercase(), name.to_lowercase());
204+
}
176205
}
177206
}

edgelet/edgelet-test-utils/src/clients/cert.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,18 @@ impl CertClient {
7474

7575
let csr = openssl::x509::X509Req::from_pem(csr).unwrap();
7676
let csr_pubkey = csr.public_key().unwrap();
77+
let csr_extensions = csr.extensions().unwrap();
7778
assert!(csr.verify(&csr_pubkey).unwrap());
7879

7980
let mut cert = openssl::x509::X509::builder().unwrap();
8081
cert.set_subject_name(csr.subject_name()).unwrap();
8182
cert.set_issuer_name(&issuer_name).unwrap();
8283
cert.set_pubkey(&csr_pubkey).unwrap();
8384

85+
for extension in csr_extensions.iter() {
86+
cert.append_extension2(extension).unwrap();
87+
}
88+
8489
let not_before = openssl::asn1::Asn1Time::from_unix(0).unwrap();
8590
let not_after = openssl::asn1::Asn1Time::days_from_now(30).unwrap();
8691

0 commit comments

Comments
 (0)