Global Scope and UAnon roles always exist

Contrary to what’s suggested in the boundary reference architecture, the global scope and roles associated with u_anon always exist, even if boundary was started under the command -skip-scopes-creation

Not sure if this is intentional behavior or not, but given that this IS happening, how do I configure boundary so that an anonymous person doesn’t have access to list the global scope?

Seeing a page like this everytime is NOT ideal. I’m tempted to just have all authentication under the global scope level.

1 Like

Deleting the Role prevents the login screen from ever showing up

The global scope must always exist and can’t be deleted - Domain Model - Scopes | Boundary by HashiCorp

I expect the login screen won’t show up when you delete u_anon because you are u_anon before authenticating to Boundary.

Any application maintaining its own authentication layer will need to allow anonymous users to authenticate, otherwise the whole thing gets a bit “chicken <-> egg”.

1 Like

I didn’t exactly delete u_anon, but rather just the role that allows u_anon to view the global scope. (i.e. the role with the name “Login and Default Grants” and description “Role created for login capability, account self-management, and other default grants for users of the global scope at its creation time”)

You will get these errors:

I still had another role set to u_anon that allowed these same permissions for an org scope, hoping that it would allow u_anon to list login options only for the org’s scope (and not the global scope)

It appears that this global scope login option is almost something that’s mandatory to show to the client, even if you don’t have any authentication options for it.

You can’t delete global scope, as the previous poster mentioned. It’s the root of everything. The CLI text should probably be updated to indicate that skipping scope creation will skip creating the default org and project scopes underneath global.

You can skip creating the initial login role with -skip-initial-login-role-creation. Since your script doesn’t pass that, it creates the initial role allowing for login.

If the initial role has already been created, you can also just update the principals and/or grants on that initial role as you like. Or just delete it. As you saw, if u_anon cannot list authentication methods, you effectively disable the web UI because you can’t log in (not sure if there is a hacky way around this or not). Remember that the web UI is just an API client…

I didn’t exactly delete u_anon

You can’t! :slight_smile: u_anon means “not an authenticated user”…it’s the only way you can control what is and isn’t available to users that are not authenticated.

An important point: if you delete the only role that allows u_anon access to authenticate action against auth methods, nobody will be able to authenticate, because any unauthenticated client is mapped to u_anon. So at that point you’d only have the KMS recovery option. But you can leave that grant alone and remove other grants you don’t want.

It appears that this global scope login option is almost something that’s mandatory to show to the client

It’s important to disambiguate which client. The web UI makes calls to do things like list auth methods so that it can present the options to the user to log in, and so that it can figure out what fields need to be available (e.g. based on auth method type) or if it needs to do something like an OIDC flow. The default grants are correlated to the needs of our default clients so that it’s easy for someone to get started.

As a contrast to the web UI, the CLI does not require listing authentication methods (unless you explicitly perform such a list) because when you authenticate it simply does a direct authentication to the auth method ID you pass in. And in general the CLI does not require any special permissions other than to perform the exact action you’re specifying.

In the end you have a large degree of control over the permissions available to both authenticated and unauthenticated users, but various clients might require various capabilities to function as designed. But you don’t need to use those clients! :slight_smile:

I think I’m starting to understand it now.

When boundary is deployed, the only scope with a determinate name is the global scope with the name global (which the clients know because it’s hardcoded). To get scopes under global (and learn the names of org scopes so you can list their authentication methods), you have to perform the search from the global scope and thus have the permission id=*;type=scope;actions=list,no-op for the global scope on the principal u_anon

I had a misconception that the boundary client could list out all this information without needing a global level scope access.

You’re right, I think this is my real problem. The Web and Client UI will show the global scope and all org scopes. I was under the impression that it only showed scopes that you could authenticate into.

For example, if the u_anon user had these grants:

  • id=*;type=scope;actions=list,no-op for global scope
  • id=*;type=auth-method;actions=authenticate,list for an org scope

Then you should be able to find and list the org scope you want to authenticate into (without needing to know any specific ids beforehand) using the commands:

  • boundary scopes list
  • boundary auth-methods list -scope-id <ID-FROM-PREVIOUS-COMMAND>
  • boundary authenticate oidc -auth-method-id <ID-FROM-PREVIOUS-COMMAND>

However, due to the default behavior of the way the desktop and web clients work, if you go to the web-admin page or desktop client, it will give you a blank screen. This is because the client is hardcoded to list auth-methods on the global scope – which you can’t do – and so you get a blank screen.

I think I can live with it for now :slight_smile:

It can!

When you recursively list, which I believe the UI does to find auth methods, each resource is individually checked for access. So you could remove that permission at global scope, and still get auth methods that can be listed by the anonymous user from downstream scopes.

Certainly this is possible via the CLI, I am not 100% sure the UI works this way but I thought so…

I don’t follow. I’m pretty sure if you list “recursively”, you need to be able to list in a hierarchal manner at the global scope first, then list at each org scope, and so on, as the default scope is global. I’m certain you still need to give u_anon the ability to list scopes at the global scope level.

Just tried this in the CLI by removing the id=*;type=scope;actions=list,no-op global scope grant. boundary auth-methods list -recursive and boundary scopes list -recursive gives an unauthorized error (which makes sense because since I don’t have these global permissions, I can’t query which orgs are in global, and thus I don’t know the org scope-id’s to query auth methods for)

Not sure if this is intended behavior or not, but it appears that the id=*;type=auth-method;actions=authenticate,list is required at the global level as well in order for boundary auth-methods list -recursive to succeed. If I were to guess, it appears that it tries to list the auth-methods on every possible scope it can find recursively, and if it can’t list the auth-methods on even one scope, it prematurely errors out with an unauthorized error. Seems like a bug.

I can’t replicate the behavior you’re describing…

I started a dev server, which gives an org scope (o_1234567890) with default permissions (which include authenticate and list on auth methods). I created a password auth method in scope o_1234567890 and verified I could see it by doing boundary auth-methods list -recursive without specifying a scope ID (so it defaulted to global). At that point I could see three auth methods as expected.

I then removed both of the auto generated roles from the global scope (first the user/default grants, then the administration role). After this I verified that boundary auth-methods list failed with 403. But boundary auth-methods list -recursive did not fail, and showed me only the auth method in scope o_1234567890 as expected.

If I repeat this and do not add an auth method in o_1234567890 and I delete the global level roles, I get a 403 listing at just the global scope as expected, and a 404 when recursively listing.

Are you sure that you have permissions granted to your user to list auth methods in your downstream organization scope? Also, do you happen to be using an old version of Boundary? This code hasn’t changed in a while but if you’re, say, pre-0.4 you may want to update.

Hmm, I’m currently using 0.5, but that’s strange. I didn’t get any 403 errors, but rather I got 401 errors saying I was unauthenticated (although I didn’t get this error when the roles were present). And I was testing this out on actual infrastructure (similar to that deployed in the reference architecture, minus the load balancers).

I’ll see if I can replicate it on a dev environment as well

Alright, I couldn’t replicate your behavior, which is weird…

Here’s the code I used once I launched boundary dev:

#Login
export BOUNDARY_ADDR="http://127.0.0.1:9200/"
export BOUNDARY_TOKEN=$(boundary authenticate password -login-name admin -auth-method-id=ampw_1234567890 -password password -keyring-type=none -format=json | jq -r ".item.attributes.token")
# Create auth method
boundary auth-methods create password -scope-id o_1234567890
# Create new role
ROLE_ID=$(boundary roles create -scope-id o_1234567890 -format json | jq -r ".item.id")
boundary roles add-principals -id $ROLE_ID -principal "u_anon"
boundary roles add-grants -id $ROLE_ID -grant "id=*;type=auth-method;actions=authenticate,list"
# Delete Generated Roles
DEFAULT_ROLE=$(boundary roles list -format json | jq -r '.items[] | select(.name=="Login and Default Grants").id')
ADMIN_ROLE=$(boundary roles list -format json | jq -r '.items[] | select(.name=="Administration").id')
boundary roles delete -id $DEFAULT_ROLE
boundary roles delete -id $ADMIN_ROLE
# Test recursive call
unset BOUNDARY_TOKEN
boundary auth-methods list --recursive --keyring-type=none # This fails
boundary auth-methods list -scope-id o_1234567890 --keyring-type=none #This succeeds

Same thing happened as usual for me.

Ah, thanks for your repro case. I realized, looking at yours, that I hadn’t actually wiped my token; I had simply removed the roles. This made all the difference!

It is indeed a bug. What’s happening is that the auth system, if a token is provided but has no permissions, is returning a 403 to the service handler. The service handler, seeing the combination of 403, a recursive request, and that authentication has been performed, still continues anyways, looking for downstream scopes with the correct permissions. This is what it should be doing.

The bug is that when it’s actually the anonymous user, the auth system returns 401 instead. This is semantically correct according to the not-always-sensible status code specifications for HTTP – maybe you’re authorized, but we can’t check because we don’t have any authentication information. So then you authenticate, and we can actually check, and in that case return a 403. (As MDN says for 401, it’s similar to 403, but in this case, authentication is possible.)

I’ll get this fixed up for the next release!

1 Like