-
Notifications
You must be signed in to change notification settings - Fork 58
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
spread/google: add support for service accounts #187
base: master
Are you sure you want to change the base?
spread/google: add support for service accounts #187
Conversation
a1696e0
to
98757d7
Compare
README.md
Outdated
backends: | ||
google: | ||
key: $(HOST:echo $GOOGLE_JSON_FILENAME) | ||
google-service-account: $(HOST:echo $GOOGLE_SERVICE_ACCOUNT) |
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.
perhaps this could be a boolean switch? The problem is that even through the key type is service_account
, the actual role associated with the identity of the request may not have the permissions to attach service account to instances. As we learned the hard way, what you need is compute.instances.setServiceAccount
permission, which wasn't set for spread user role in our GCP project.
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.
Alternative I discussed with @sergiocazzolato is to maybe have this as a property of the actualy system eg. attach-service-account: true
, which then defaults to using the service account client_email
present in the client authentication file.
spread/project.go
Outdated
@@ -82,6 +82,9 @@ type Backend struct { | |||
|
|||
Priority OptionalInt | |||
Manual bool | |||
|
|||
// Only relevant for the Google backend | |||
GoogleServiceAccount string `yaml:"google-service-account"` |
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.
Looking at existing keys above, this would be the first that namespaces the name (prefix Google
/ google-
) based on the backend, existing backend-specific fields (Allocate
, Discard
, Memory
, Plan
, Location
, Storage
) all don't have prefixes that mention their backend.
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 would suggest adding it as ServiceAccount string
(with service-account
in YAML) next to the existing google-specific members (Plan
, Location
, Storage
)?
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 field has now been moved to the system level
// account to the instance | ||
params["serviceAccounts"] = []googleParams{{ | ||
"email": serviceAccount, | ||
"scopes": []string{"https://www.googleapis.com/auth/cloud-platform"}, |
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 the scopes also need to be parameterized (fewer/more/different scopes), or is that the only sensible value to be used when using Spread?
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.
AFAIU it should match the same default scope we use when setting up the client https://github.com/snapcore/spread/blob/ded9133cdbceaf01f8a1c9decf6ff9ea56e194d6/spread/google.go#L776
README.md
Outdated
@@ -894,6 +894,22 @@ Service accounts are best as they can be further constrained and not be | |||
associated with your overall authenticated access. Do not ship your own | |||
credentials to remote systems. | |||
|
|||
In order to attach a service account to the instance created by spread use the |
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 make "service account" a link to documentation from Google Cloud what a service account is and when one would use it?
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.
This is mentioned in the paragraph just above.
Add support for attaching service accounts to the instances created in GCP. Signed-off-by: Maciej Borzecki <[email protected]>
98757d7
to
07c7be1
Compare
@thp-canonical @sergiocazzolato @ZeyadYasser I have reworked this a bit, please have a look. The backend level field was confusing and I've changed this completely. Since there is no reasonable scenario in which the service account would use a different 'email' address than one in the key, the actual value gets derived from the authentication key. The process is identical to what golang.org/x/oauth2/google package does. Now, a system level property governs whether you want to attach a service account to an instance or not. This distinctions is still needed, as the IAM role assined to the account may not permit to attach service accounts, and so just attempting to attach it by default one would not be able to create any instances if the permissions scope was intentionally limited. |
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.
Looks good, two comments.
key: $(HOST:echo $GOOGLE_JSON_FILENAME) | ||
... | ||
systems: | ||
- system-with-service-account: |
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'd make this more realistic or more clarly a placeholder text.
// already a raw JSON blob | ||
raw = []byte(p.backend.Key) | ||
} else { | ||
raw, err = ioutil.ReadFile(p.backend.Key) |
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 think this is just os.ReadFile now
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.
spread is go 1.13 😞
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 am bit worried of giving too much privileges (see, edit, configure, and delete Google Cloud data) [1] to test instances. I feel that explicitly passing a dedicated service account/scopes could be safer.
I might be missing context here that would make this a non-issue, please correct me if I am wrong.
[1] https://developers.google.com/identity/protocols/oauth2/scopes#ml
// account to the instance | ||
params["serviceAccounts"] = []googleParams{{ | ||
"email": p.serviceAccount, | ||
"scopes": []string{"https://www.googleapis.com/auth/cloud-platform"}, |
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.
This scope feels too powerful to give to an instance running, Do we know the minimum scopes we need for ubuntu pro?
if the scope should match the default scope for the key, would it make sense to avoid attaching the service account from the auth key to the machine and instead explicitly pass a less privileged (setup by IS) service account with minimum set of scopes needed?
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.
This is the exact same scope we use when creating GCP client in https://github.com/snapcore/spread/blob/master/spread/google.go#L776 it's also the scope of the token, but the actual permissions. What you can do is not driven by the token scope but by the IAM role assigned to your account. In fact, your application default account, or even the github account we use in default in snapd spred are unable to attach the instances because they lack the necessary permissions in their assigned roles roles.
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.
This is the exact same scope we use when creating GCP client in https://github.com/snapcore/spread/blob/master/spread/google.go#L776
But the GCP client is spread, right? and the key owner is the one invoking spread (consciously) so it is expected and not a security issue here.
it's also the scope of the token, but the actual permissions.
Yes, but since the user can run spread that means their attached svc account can do CRUD operations on GCP instances.
My worry, is giving this power to an Ubuntu instance with lots of installed software (large attack surface), all of which would be able to do CRUD operations on the company's internal GCP account. The attack surface grows from just spread's code base, to Ubuntu + a bunch of installed software.
Again, I might be missing a puzzle piece here or some context that could make this concern a non issue.
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.
You cannot attach a service account unless the role assigned to your account is allowed to do so. The application default account all of use does not have that. The service account used by spread runners does not have that either. In fact you even won't be able to start an instance with the service account attached, all you get back is:
cannot allocate new Google server for ubuntu-pro-22.04-64: required
'compute.instances.setServiceAccount' permission for 'projects/snapd-spread/zones/us-east1-b/instances/jun250926-154636'
You are not giving power to anyone, unless you generate a key for them in GCP admin console and give them the key they can use to pass to spread.
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 getting my concerns from https://cloud.google.com/iam/docs/attach-service-accounts:
When the resource needs to access other Google Cloud services and resources, it uses its attached service account as its identity. For example, if you attach a service account to a Compute Engine instance, and the applications on the instance use a client library to call Google Cloud APIs, those applications automatically authenticate as the attached service account.
but since you tested it on launched machine, then I am confusing this with something else.
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.
Yes, that's the whole point of attaching a service account to the machine. This way we as long as the account we use entitled to use Ubuntu Pro, the ubuntu-advantage-client will be able to automatically enable relevant support at boot time. There is no need to share or carry yet another token.
Add support for attaching service accounts to the instances created in GCP.
And we can now automatically get access to Ubuntu Pro features (if your account permits it):