-
Notifications
You must be signed in to change notification settings - Fork 120
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
CCT-67: Anonymous registration #3370
Conversation
6a66adb
to
cff8198
Compare
fafd80b
to
4ca30ee
Compare
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.
Thanks for this PR. I have several comments, questions and requests.
4ca30ee
to
19dcdc1
Compare
74ec02c
to
4904fde
Compare
The code for it was removed in 3095f59 (2021-09).
rhsmcertd is not related to D-Bus server.
The organization may be a None.
4904fde
to
06d3c39
Compare
06d3c39
to
321d38d
Compare
Force-push change: install entitlement certificates after registering with anonymous organization. subscription-manager/src/subscription_manager/scripts/rhsmcertd_worker.py Lines 282 to 289 in 321d38d
|
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.
Thanks for update! 👍 I have few comments and requests.
src/rhsm/connection.py
Outdated
:param metadata: string with base64 encoded metadata | ||
:param signature: string with base64 encoded signature | ||
:return: string with JWT | ||
def get_cloud_jwt(self, cloud_id: str, metadata: str, signature: str) -> Dict[str, Any]: |
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 know that camelCase is not Pythonic, but I would keep names of method consistent.
|
||
payload: str = content["token"].split(".")[1] | ||
# JWT does not use the padding, base64.b64decode requires it. | ||
payload = f"{payload}===" |
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.
We have almost the same code here: https://github.com/candlepin/subscription-manager/blob/main/src/cloud_what/providers/gcp.py#L275 . I would do some refactoring to remove duplicated code.
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.
Do you think it is necessary? This implementation is much smaller and quite self-contained. I am not sure it is worth extracting both into a shared implementation, since we're only doing this on two places.
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.
OK
|
||
|
||
class AnonymousCertificateManager: | ||
"""Manage anonymous certificates. |
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 would emphasize that these certificates are entitlement certificates in this doc string.
:param jwt: The Bearer token sent by Candlepin. | ||
""" | ||
log.debug("Obtaining anonymous entitlement certificates and keys") | ||
certificates: List[Dict] = self.uep.getCertificates(consumer_uuid=uuid, jwt=jwt) |
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.
When no entitlement certificates are installed, then it does not make sense to continue with following steps. I would print some warning message, when no entitlement certificates was downloaded.
) | ||
|
||
update_repo = repolib.RepoUpdateActionCommand() | ||
update_repo_report: repolib.RepoActionReport = update_repo.perform() |
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 report update_repo_report
could be None, but you don't check for that in following code.
@@ -96,6 +96,10 @@ def getConsumerName(self) -> str: | |||
def getSerialNumber(self) -> int: | |||
return self.x509.serial | |||
|
|||
def getConsumerOwner(self) -> str: | |||
subject: dict = self.x509.subject | |||
return subject.get("O") |
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.
Maybe, this deserves some constant with comment, but I can see that other parts of code. Up to you. We can deffer improvements of this code.
|
||
log.debug("Trying to detect cloud provider") |
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 did you remove this debug log from this function?
log.debug("This system is already registered, skipping automatic registration.") | ||
else: | ||
print(_("Registering the system")) | ||
log.debug("Starting automatic registration.") |
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 would move the debug log to the _auto_register()
to keep everything together.
if token["tokenType"] == "CP-Cloud-Registration": | ||
try: | ||
_auto_register_standard(uep=uep, token=token) | ||
except Exception: |
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:
except Exception as err:
log.exception(f"Standard automatic registration failed: {err}.")
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 is not needed, the log.exception()
will print out the full traceback, so we are getting the actual exception and its stack.
try: | ||
_auto_register_anonymous(uep=uep, token=token) | ||
cache.CloudTokenCache.delete_cache() | ||
except Exception: |
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.
Similar suggestion here.
* Card ID: CCT-67 - /cloud/authorize?version=2: New - /consumers/{uuid}/certificates: Added 'Authorization' header
321d38d
to
69013e9
Compare
* Card ID: CCT-67 The token we receive from Candlepin is valid for two days and should be kept even when the system is restarted. This cache files is used to make sure it persists.
* Card ID: CCT-67 An abstraction managing anonymous entitlement certificates.
This patch creates a system for exit codes used by the worker. This way the C wrapper may be able to understand what happened inside of the application and alter its behavior.
* Card ID: CCT-67 This patch implements the standard and anonymous flows for automatic cloud registration.
* Card ID: CCT-67
* Card ID: CCT-67 The delay was introduced in early versions of the code when Python was not reliable for long-running tasks. Since we want to make automatic registration in both standard and anonymous flow to be as fast as possible, this delay is removed. This splay period is now performed by the Python code in case the we have obtained the anonymous entitlement certificates; before we ask for the identity certificate.
* Card ID: CCT-66 During the first phase of anonymous cloud registration, the system has valid entitlement certificates that aren't associated with any consumer. We shouldn't be reporting missing identity. Previously this was an error state that was not valid, but with automatic registration it is possible to have a system consuming content that does not have an identity, for a transition period before it is part of an anonymous or claimed organization.
69013e9
to
4820e5f
Compare
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.
LGTM, Thanks for all updates.
|
||
payload: str = content["token"].split(".")[1] | ||
# JWT does not use the padding, base64.b64decode requires it. | ||
payload = f"{payload}===" |
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.
OK
This PR implements the v2 flow for automatic cloud registration. Please see the individual commits for comments, I've tried to keep them all separate to describe the tasks that needed to happen. And I'd like to specifically ask for detailed review of the C code, that may need adjustments.
Verify steps:
candlepin.local
to a running instance ofghcr.io/ptoscano/candlepin-unofficial:latest
using your/etc/hosts
(make sure the instance is set into Hosted mode)/etc/rhsm/ca/
rhsm.conf
cloud-what
'saws.py
to point to local mock HTTP server for AWS metadata.rhsmcertd-worker --auto-register
and let the system anonymously register. Complete the flow to leave the system left with anonymous identity.rhsmcertd-worker
and let the system replace anonymous identity with proper one.