[NBS Docs] Refactor Top Level Permissions Docs
Signed-off-by: Andre Wanlin <awanlin@spotify.com>
This commit is contained in:
@@ -4,14 +4,8 @@ title: Getting Started
|
||||
description: How to get started with the permission framework as an integrator
|
||||
---
|
||||
|
||||
If you prefer to watch a video instead, you can start with this video introduction:
|
||||
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/EQr9tFClgG0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
|
||||
:::note Note
|
||||
|
||||
This video was recorded in the January 2022 Contributors Session using `@backstage/create-app@0.4.14`. Some aspects of the demo may have changed in later releases.
|
||||
|
||||
:::info
|
||||
This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./getting-started--old.md) instead, and [consider migrating](../../backend-system/building-backends/08-migrating.md)!
|
||||
:::
|
||||
|
||||
Backstage integrators control permissions by writing a policy. In general terms, a policy is simply an async function which receives a request to authorize a specific action for a user and (optional) resource, and returns a decision on whether to authorize that permission. Integrators can implement their own policies from scratch, or adopt reusable policies written by others.
|
||||
@@ -22,13 +16,7 @@ The permissions framework depends on a few other Backstage systems, which must b
|
||||
|
||||
### Upgrade to the latest version of Backstage
|
||||
|
||||
The permissions framework itself is new to Backstage and still evolving quickly. To ensure your version of Backstage has all the latest permission-related functionality, it’s important to upgrade to the latest version. The [Backstage upgrade helper](https://backstage.github.io/upgrade-helper/) is a great tool to help ensure that you’ve made all the necessary changes during the upgrade!
|
||||
|
||||
### Enable service-to-service authentication
|
||||
|
||||
Service-to-service authentication allows Backstage backend code to verify that a given request originates from elsewhere in the Backstage backend. This is useful for tasks like collation of catalog entities in the search index. This type of request shouldn’t be permissioned, so it’s important to configure this feature before trying to use the permissions framework.
|
||||
|
||||
To set up service-to-service authentication, follow the [service-to-service authentication docs](../auth/service-to-service-auth.md).
|
||||
To ensure your version of Backstage has all the latest permission-related functionality, it’s important to upgrade to the latest version. The [Backstage upgrade helper](https://backstage.github.io/upgrade-helper/) is a great tool to help ensure that you’ve made all the necessary changes during the upgrade!
|
||||
|
||||
### Supply an identity resolver to populate group membership on sign in
|
||||
|
||||
@@ -38,33 +26,40 @@ Like many other parts of Backstage, the permissions framework relies on informat
|
||||
|
||||
[The IdentityResolver docs](../auth/identity-resolver.md) describe the process for resolving group membership on sign in.
|
||||
|
||||
## Optionally add cookie-based authentication
|
||||
## Test Permission Policy
|
||||
|
||||
Asset requests initiated by the browser will not include a token in the `Authorization` header. If these requests check authorization through the permission framework, as done in plugins like TechDocs, then you'll need to set up cookie-based authentication. Refer to the ["Authenticate API requests"](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/authenticate-api-requests.md) tutorial for a demonstration on how to implement this behavior.
|
||||
To get help validate the permission framework is setup we'll create a Test Permission Policy:
|
||||
|
||||
## Integrating the permission framework with your Backstage instance
|
||||
1. Backstage ships with a default Allow All Policy, we want to remove that as it would override our Test Permission Policy. To do this remove the following line:
|
||||
|
||||
### 1. Set up the permission backend
|
||||
|
||||
The permissions framework uses a new `permission-backend` plugin to accept authorization requests from other plugins across your Backstage instance. The Backstage backend does not include this permission backend by default, so you will need to add it:
|
||||
|
||||
1. Add `@backstage/plugin-permission-backend` as a dependency of your Backstage backend:
|
||||
|
||||
```bash title="From your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-permission-backend
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
// permission plugin
|
||||
backend.add(import('@backstage/plugin-permission-backend/alpha'));
|
||||
/* highlight-remove-start */
|
||||
backend.add(
|
||||
import('@backstage/plugin-permission-backend-module-allow-all-policy'),
|
||||
);
|
||||
/* highlight-remove-end */
|
||||
```
|
||||
|
||||
2. Add the following to a new file, `packages/backend/src/plugins/permission.ts`. This adds the permission-backend router, and configures it with a policy which allows everything.
|
||||
2. Now we need to add the `@backstage/backend-plugin-api` package:
|
||||
|
||||
```typescript title="packages/backend/src/plugins/permission.ts"
|
||||
import { createRouter } from '@backstage/plugin-permission-backend';
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/backend-plugin-api
|
||||
```
|
||||
|
||||
3. Next we will create an `extensions` folder under `packages/backend/src`
|
||||
4. In this new `extensions` folder we will add a new file called: `permissionsPolicyExtension.ts`
|
||||
5. Copy the following into the new `permissionsPolicyExtension.ts` file:
|
||||
|
||||
```ts title="packages/backend/src/extensions/permissionsPolicyExtension.ts"
|
||||
import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
import {
|
||||
AuthorizeResult,
|
||||
PolicyDecision,
|
||||
AuthorizeResult,
|
||||
} from '@backstage/plugin-permission-common';
|
||||
import { PermissionPolicy } from '@backstage/plugin-permission-node';
|
||||
import { Router } from 'express';
|
||||
import { PluginEnvironment } from '../types';
|
||||
import { policyExtensionPoint } from '@backstage/plugin-permission-node/alpha';
|
||||
|
||||
class TestPermissionPolicy implements PermissionPolicy {
|
||||
async handle(): Promise<PolicyDecision> {
|
||||
@@ -72,48 +67,34 @@ The permissions framework uses a new `permission-backend` plugin to accept autho
|
||||
}
|
||||
}
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
return await createRouter({
|
||||
config: env.config,
|
||||
logger: env.logger,
|
||||
discovery: env.discovery,
|
||||
policy: new TestPermissionPolicy(),
|
||||
identity: env.identity,
|
||||
});
|
||||
}
|
||||
export default createBackendModule({
|
||||
pluginId: 'permission',
|
||||
moduleId: 'permission-policy',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: { policy: policyExtensionPoint },
|
||||
async init({ policy }) {
|
||||
policy.setPolicy(new TestPermissionPolicy());
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
3. Wire up the permission policy in `packages/backend/src/index.ts`. [The index in the example backend](https://github.com/backstage/backstage/blob/master/packages/backend/src/index.ts) shows how to do this. You’ll need to import the module from the previous step, create a plugin environment, and add the router to the express app:
|
||||
6. We now need to register this in the backend. We will do this by adding the follow line:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
import proxy from './plugins/proxy';
|
||||
import techdocs from './plugins/techdocs';
|
||||
import search from './plugins/search';
|
||||
// permission plugin
|
||||
backend.add(import('@backstage/plugin-permission-backend/alpha'));
|
||||
/* highlight-add-next-line */
|
||||
import permission from './plugins/permission';
|
||||
|
||||
async function main() {
|
||||
const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs'));
|
||||
const searchEnv = useHotMemoize(module, () => createEnv('search'));
|
||||
const appEnv = useHotMemoize(module, () => createEnv('app'));
|
||||
/* highlight-add-next-line */
|
||||
const permissionEnv = useHotMemoize(module, () => createEnv('permission'));
|
||||
// ..
|
||||
|
||||
apiRouter.use('/techdocs', await techdocs(techdocsEnv));
|
||||
apiRouter.use('/proxy', await proxy(proxyEnv));
|
||||
apiRouter.use('/search', await search(searchEnv));
|
||||
/* highlight-add-next-line */
|
||||
apiRouter.use('/permission', await permission(permissionEnv));
|
||||
// ..
|
||||
}
|
||||
backend.add(import('./extensions/permissionPolicyExtension'));
|
||||
```
|
||||
|
||||
### 2. Enable and test the permissions system
|
||||
You now have a Test Permission Policy in place, this will help us test that the permission framework is working in the next section.
|
||||
|
||||
Now that the permission backend is running, it’s time to enable the permissions framework and make sure it’s working properly.
|
||||
## Enable and test the permissions system
|
||||
|
||||
Now lets test end to end that the permissions framework is setup and configured properly we will use the Test Permission Policy we create above as is, then modify it do deny access which will confirm everything is working as expected. Here's how to do that:
|
||||
|
||||
1. Set the property `permission.enabled` to `true` in `app-config.yaml`.
|
||||
|
||||
@@ -122,44 +103,11 @@ Now that the permission backend is running, it’s time to enable the permission
|
||||
enabled: true
|
||||
```
|
||||
|
||||
2. Update the PermissionPolicy in `packages/backend/src/plugins/permission.ts` to disable a permission that’s easy for us to test. This policy rejects any attempt to delete a catalog entity:
|
||||
2. Now run `yarn dev`, Backstage should load up in your browser
|
||||
3. You should see that you have entities in your Catalog, pretty simple
|
||||
4. Let's change this line in our Test Permission Policy `return { result: AuthorizeResult.ALLOW };` to be `return { result: AuthorizeResult.DENY };`
|
||||
5. Run `yarn dev` once again, Backstage should load up in your browser
|
||||
6. This time you should not see any entities in your Catalog, if you do then something went wrong along the way and you'll need to review the steps above
|
||||
7. Revert the change we made in step 4 so that the line looks like this: `return { result: AuthorizeResult.ALLOW };`
|
||||
|
||||
```ts title="packages/backend/src/plugins/permission.ts"
|
||||
import { createRouter } from '@backstage/plugin-permission-backend';
|
||||
import {
|
||||
AuthorizeResult,
|
||||
PolicyDecision,
|
||||
} from '@backstage/plugin-permission-common';
|
||||
/* highlight-remove-next-line */
|
||||
import { PermissionPolicy } from '@backstage/plugin-permission-node';
|
||||
/* highlight-add-start */
|
||||
import {
|
||||
PermissionPolicy,
|
||||
PolicyQuery,
|
||||
} from '@backstage/plugin-permission-node';
|
||||
/* highlight-add-end */
|
||||
import { Router } from 'express';
|
||||
import { PluginEnvironment } from '../types';
|
||||
|
||||
class TestPermissionPolicy implements PermissionPolicy {
|
||||
/* highlight-remove-next-line */
|
||||
async handle(): Promise<PolicyDecision> {
|
||||
/* highlight-add-start */
|
||||
async handle(request: PolicyQuery): Promise<PolicyDecision> {
|
||||
if (request.permission.name === 'catalog.entity.delete') {
|
||||
return {
|
||||
result: AuthorizeResult.DENY,
|
||||
};
|
||||
}
|
||||
/* highlight-add-end */
|
||||
|
||||
return { result: AuthorizeResult.ALLOW };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Now that you’ve made this change, you should find that the unregister entity menu option on the catalog entity page is disabled.
|
||||
|
||||

|
||||
|
||||
Now that the framework is fully configured, you can craft a permission policy that works best for your organization by utilizing a provided authorization method or by [writing your own policy](./writing-a-policy.md)!
|
||||
Congratulations! Now that the framework is fully configured, you can craft a permission policy that works best for your organization by [writing your own policy](./writing-a-policy.md)!
|
||||
|
||||
Reference in New Issue
Block a user