-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support read-write device.id in tedge cert/connect #3326
base: main
Are you sure you want to change the base?
feat: support read-write device.id in tedge cert/connect #3326
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The command to create a CSR must also be updated to set the device id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the device id has been set using tedge config set device.id
, then the device id should no more be mandatory for tedge cert create
.
We also need to take care of the paths for the cloud specific certificates.
For instance, the following sequence of command is error prone:
# Trying to create a certificate for an unknown cloud profile (okay: the error is detected)
$ tedge cert create --device-id demo-c8y c8y --profile foo
Error: missing configuration parameter
Caused by:
Unknown profile `foo` for the multi-profile property c8y
# Creating the cloud profile
$ tedge config set c8y.device.id device-c8y-foo --profile foo
# Now that the cloud profile exists, the cert creat command runs
# BUT
# - --device-id is required while set in the config
# - the value set on the command line erases the config
# - the certificate is created globally (because no specific paths were configured for this profile)
$ tedge cert create --device-id some-other-device-id c8y --profile foo
Error: failed to create a test certificate for the device some-other-device-id.
Caused by:
A certificate already exists and would be overwritten.
Existing file: "/etc/tedge/device-certs/demo-device-888.pem"
Run `tedge cert remove` first to generate a new certificate.
@didier-wenzek
For the rest, I would like to implement to have the consistent behavour as However, on the condition, if |
In that case this is a bug.
Perfect. One just to be cautious taking the most specific device id (i.e. the id for the requested cloud and profile if given).
Yes raising an error is the way to go. But make sure the comparison is done on the device id specific for the requested cloud. I.e. if |
Codecov ReportAttention: Patch coverage is Additional details and impacted files📢 Thoughts on this report? Let us know! |
Robot Results
|
7dcb459
to
77e1ecd
Compare
Signed-off-by: James Rhodes <james.rhodes@cumulocity.com>
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
Examples: `tedge cert create --device-id foo` -> `device.id` is set to foo `tedge cert create --device-id bar c8y` -> `c8y.device.id` is set to bar `tedge cert create --device-id baz c8y --profile new` -> `c8y.profiles.new.device.id` is set to baz Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
* tedge connect c8y uses device.id directly. The CN from certificate is no longer used to determine device.id * tedge connect c8y returns an error if device.id mismatches the certificate's CN when auth method is certificate Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
77e1ecd
to
247d7f8
Compare
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
let key = profile.map(|name| name.to_string()); | ||
let c8y_dto = dto.c8y.try_get(key.as_deref(), "c8y")?; | ||
if c8y_dto.device.id.is_some() { | ||
Err(MismatchedDeviceId { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this error case really useful?
- It's used only in this function
- and the error case for no device id at all is raised using
anyhow!()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wanted to find a better solution here. Using anyhow!()
is definitely fine, even I used it at very first draft. But it will cause repeating the same long error message multiple times in the code. Anyway, I don't like that I had to add MismatchedDeviceId
under TEdgeError
as well, so using anyhow!()
may be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplified in 99620aa
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm now surprised that there no more conflict detection at all, when the device id is provided on the command line and in the config, but with different values. Wouldn't be better to raise an error stressing the conflict?
Okay after having read #3326 (comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The feature is working as expected. But, simplifying the device id validation done in the tedge cert
commands as suggested by @didier-wenzek would go a long way in making that function comprehendible, and easy to review.
let cmd = CreateCertCmd { | ||
id, | ||
id: get_device_id(id, &config, &context.config_location, &cloud)?, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I don't have any objections to this, I'm a bit surprised to see this device.id
match validation here. I was under the impression that a value provided in the cli would simply override the existing value in the config and any validation would happen only during tedge connect
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was under the impression that a value provided in the cli would simply override the existing value in the config
I'm actually now reconsidering this. If user run like below:
tedge config set device.id foo
tedge cert create --device-id bar
- If cert/key doesn't exist, the command creates cert/key and set
device.id
tofoo
. - If cert/key already exists, the command returns an error (known behaviour). No overwriting either id or cert. So, it cannot mess up already existing cert.
Does it really hurt users to overwrite the device id by tedge cert
although they configured before? I guess not. Also, the command tells device.id
is set to foo
.
In that case, error scenario is only there are no input id AND no config id.
any validation would happen only during tedge connect.
The validation required in tedge connect
is a different level. It checks if CN matches the configured device.id
(or profile version c8y.device.id
/ c8y.profiles.<profile>.device.id
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be simplified like this.
fn get_device_id(
id: Option<String>,
config: &TEdgeConfig,
cloud: &Option<Cloud>,
) -> Result<String, anyhow::Error> {
let config_id = config.device_id(cloud.as_ref()).ok();
match (id, config_id) {
(None, None) => Err(anyhow!("No device ID is provided. Use `--device-id <name>` option to specify the device ID.")),
(None, Some(config_id)) => Ok(config_id.into()),
(Some(input_id), None) => Ok(input_id),
(Some(input_id), Some(_config_id)) => Ok(input_id),
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, overwriting is the simpler contract to enforce. Keeps things simple at the code level as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplified in 99620aa
#[test_case("test", None, None, toml::toml!{ | ||
[device] | ||
id = "test" | ||
})] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting suggestion:
#[test_case("test", None, None, toml::toml!{ | |
[device] | |
id = "test" | |
})] | |
#[test_case( | |
"test", | |
None, | |
None, | |
toml::toml!{ | |
[device] | |
id = "test" | |
} | |
)] |
Same for the rest of the test cases as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which formatter are you using and forces this? My IDE doesn't, it's a pain to do all manually 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was just manually formatted as cargo fmt
doesn't touch stuff defined inside macros (test_case
in this case). I found that laset few test cases really hard to read, hence suggested this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in 99620aa
@@ -59,6 +59,8 @@ mod tests { | |||
use std::path::Path; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if it'd be safer to call set_device_id
from this renew
command execute()
as well so that any configuration from an older version of tedge
is updated when the cert is renewed with the newer version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 56986f2
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code looks good and simpler thanks to the latest commits. However, I still need some time to test the updated cli.
crates/common/tedge_config/src/tedge_config_cli/tedge_config.rs
Outdated
Show resolved
Hide resolved
crates/common/tedge_config/src/tedge_config_cli/tedge_config.rs
Outdated
Show resolved
Hide resolved
crates/common/tedge_config/src/tedge_config_cli/tedge_config.rs
Outdated
Show resolved
Hide resolved
let key = profile.map(|name| name.to_string()); | ||
let c8y_dto = dto.c8y.try_get(key.as_deref(), "c8y")?; | ||
if c8y_dto.device.id.is_some() { | ||
Err(MismatchedDeviceId { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm now surprised that there no more conflict detection at all, when the device id is provided on the command line and in the config, but with different values. Wouldn't be better to raise an error stressing the conflict?
Okay after having read #3326 (comment).
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
Specify the external IDs of the SmartREST 1.0 templates as shown below: | ||
|
||
```sh | ||
sudo tedge config set c8y.smartrest1.templates template-1,template-2 | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion:
You have to register on the device all the SmartREST 1.0 templates you plan to use.
This can be done by providing a comma-separated list of the external IDs of the SmartREST 1.0 templates:
sudo tedge config set c8y.smartrest1.templates template-1,template-2
This can also be done by adding these template IDs one by one;
sudo tedge config add c8y.smartrest1.templates template-1
sudo tedge config add c8y.smartrest1.templates template-2
Proposed changes
This PR aims to open up
device.id
as read-write key. This is the last piece of supporting basic authentication, as it needsdevice.id
but not need for device cert.TODOs:
tedge cert/connect part
tedge cert create
writesdevice.id
intedge.toml
explicitly.tedge connect
returns an error ifdevice.id
mismatches the certificate's CN. The only exception is whenc8y.auth_mode
isbasic
.smart_rest_one
system test to confirm thattedge connect c8y
usesdevice.id
directly when using basic auth.tedge cert create-csr
also setsdevice.id
if not configured.tedge cert create
should work without--device-id
option whendevice.id
is already set.Don't overwrite a certificate andIf a certificate exists already in the given path, anyway it will not be overwritten (known behavour)device.id
when the values of option--device-id
and configdevice.id
are conflicting. This case should return an error.tedge_config part (originally started in the PR #3318 by @jarhodes314 )
get_device_id_from_config()
function totedge_config
to keepconfig.device.id()
as private. refactor: support writable device ids #3318 (comment)doc part
Types of changes
Paste Link to the issue
#3242
Checklist
cargo fmt
as mentioned in CODING_GUIDELINEScargo clippy
as mentioned in CODING_GUIDELINESFurther comments