> ## Documentation Index
> Fetch the complete documentation index at: https://docs.siftstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Set up attribute-based access policies

> Use Data Access Governance (DAG) to control access to Sift resources.

export const MintTable = ({columns = [], rows = [], columnWidths = []}) => {
  const pushTextWithLineBreaks = (parts, text, keyBase) => {
    const segments = String(text).split(/\\n|\n/);
    segments.forEach((segment, idx) => {
      if (segment) {
        parts.push(<span key={`${keyBase}-text-${idx}`}>{segment}</span>);
      }
      if (idx < segments.length - 1) {
        parts.push(<br key={`${keyBase}-br-${idx}`} />);
      }
    });
  };
  const parseMarkdown = text => {
    if (text === null || text === undefined) return "";
    const str = String(text);
    const parts = [];
    let lastIndex = 0;
    const pattern = /(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*|\[([^\]]+)\]\(([^)]+)\))/g;
    let match;
    while (true) {
      match = pattern.exec(str);
      if (match === null) {
        break;
      }
      if (match.index > lastIndex) {
        pushTextWithLineBreaks(parts, str.substring(lastIndex, match.index), `before-${lastIndex}`);
      }
      const fullMatch = match[0];
      if (fullMatch.startsWith("`") && fullMatch.endsWith("`")) {
        parts.push(<code key={match.index}>{fullMatch.slice(1, -1)}</code>);
      } else if (fullMatch.startsWith("**") && fullMatch.endsWith("**")) {
        parts.push(<strong key={match.index}>{fullMatch.slice(2, -2)}</strong>);
      } else if (fullMatch.startsWith("*") && fullMatch.endsWith("*")) {
        parts.push(<em key={match.index}>{fullMatch.slice(1, -1)}</em>);
      } else if (fullMatch.startsWith("[")) {
        const linkText = match[2];
        const linkUrl = match[3];
        parts.push(<a key={match.index} href={linkUrl} className="text-black-600 dark:text-black-400">
            {linkText}
          </a>);
      }
      lastIndex = pattern.lastIndex;
    }
    if (lastIndex < str.length) {
      pushTextWithLineBreaks(parts, str.substring(lastIndex), `tail-${lastIndex}`);
    }
    if (parts.length > 0) {
      return parts;
    }
    const plainParts = [];
    pushTextWithLineBreaks(plainParts, str, "plain");
    return plainParts.length ? plainParts : str;
  };
  const safeColumns = Array.isArray(columns) ? columns : [];
  const safeRows = Array.isArray(rows) ? rows : [];
  const safeColumnWidths = Array.isArray(columnWidths) ? columnWidths : [];
  const hasColumnWidths = safeColumnWidths.some(w => w !== null && w !== undefined && w !== "");
  const toCssWidth = width => typeof width === "number" ? `${width}px` : String(width);
  const getColumnStyle = idx => {
    const rawWidth = safeColumnWidths[idx];
    if (rawWidth === null || rawWidth === undefined || rawWidth === "") {
      return undefined;
    }
    const width = toCssWidth(rawWidth);
    return {
      width,
      minWidth: width
    };
  };
  const containerStyle = hasColumnWidths ? undefined : {
    overflowX: "auto"
  };
  const tableStyle = hasColumnWidths ? {
    tableLayout: "fixed",
    width: "100%"
  } : {
    width: "max-content",
    minWidth: "100%"
  };
  if (!Array.isArray(columns) || !Array.isArray(rows) || !Array.isArray(columnWidths)) {
    console.warn("MintTable received invalid props:", {
      columns,
      rows,
      columnWidths
    });
  }
  if (!safeColumns.length && !safeRows.length) {
    return null;
  }
  return <div className="mint-table-container" style={containerStyle}>
      <table style={tableStyle}>
        {hasColumnWidths && <colgroup>
            {safeColumns.map((_, idx) => {
    const style = getColumnStyle(idx);
    return <col key={idx} style={style} />;
  })}
          </colgroup>}
        <thead>
          <tr>
            {safeColumns.map((col, idx) => <th key={idx} className="text-left" style={getColumnStyle(idx)}>
                <b>{parseMarkdown(col)}</b>
              </th>)}
          </tr>
        </thead>
        <tbody>
          {safeRows.map((row, rIdx) => {
    const safeRow = Array.isArray(row) ? row : [];
    return <tr key={rIdx}>
                {safeRow.map((cell, cIdx) => <td key={cIdx} style={getColumnStyle(cIdx)}>
                    {parseMarkdown(cell)}
                  </td>)}
              </tr>;
  })}
        </tbody>
      </table>
    </div>;
};

Sift Data Access Governance (DAG) lets you define fine-grained access control policies based on attributes assigned to users and resources. Setting up DAG requires three sequential steps: creating user attributes, creating resource attributes, and creating a policy that connects them.

## Before you begin

* You have an **Admin** role.
* You are familiar with how [Sift organizes data into Assets, Channels, and Runs](/documentation/get-started/data-model).

## How DAG setup works

DAG controls access to Sift resources by evaluating attributes on users, user groups, and resources against policies you define. You can protect **Assets**, **Channels**, and **Runs** with DAG.

Setup follows a deliberate sequence: label users (or user groups) and resources with attributes, then define a policy that connects them. No access changes occur until a policy is active.

You can label users individually or label a user group. Group attributes work well when an attribute applies to the whole team, membership turns over frequently, or your identity provider only exposes attributes at the group level. Polices can reference a user's individual attributes and the group attributes for groups that a user is a member of. Assigning attributes to groups instead of individuals avoids having to maintain sets of attributes across individual users.

For example, suppose your organization runs a sensitive satellite program called `Artemis`, and only engineers with the correct clearance should access its telemetry data in Sift. Here's how DAG handles it:

1. Create a user attribute `clearance` (type: Enum Set) and assign \[`Artemis`, `Apollo`] to the cleared engineers. This labels the user. No access changes yet.
2. Create a resource attribute `program_classification` (type: Enum) and assign Artemis to the relevant Assets and Channels. This labels the resource. No access changes yet.
3. Create a policy that grants access only when a user's `clearance` contains the resource's `program_classification`. Access changes immediately once the policy is active.

Now only engineers whose `clearance` includes `Artemis` can access the Artemis resources. Others see nothing, even if their RBAC role would otherwise allow it.

## Step 1: Create and assign a user attribute

### Create a user attribute

1. Click your profile icon.
2. Select **Manage**.
3. In **Access control**, click **User attributes**.
4. Click **Create User Attribute**.
5. In the **Type** list, select a [data type](/documentation/reference/manage/authorization-models-settings#attribute-data-types).
6. In the **Name** box, enter a name for the attribute. Use a name tied to real concepts in your organization so that someone reading a policy can immediately understand what the attribute means.
7. Optional: In the **Description** box, enter a description to clarify how the attribute is intended to be used in policies.
8. Click **Save**.

### Assign a user attribute

Assigning this attribute does not change access. It only labels the user so that a policy can later reference this attribute.

1. In **Access Control**, click **User Attributes**.
2. In the **User attributes** table, locate the attribute to use.
3. Click <Icon icon="ellipsis-vertical" /> **Options**, and then select **Assign**.
4. In **Assign User Attributes**, in **Groups** or **Users**, select a group or user, and click **Update**.
   * You can select any user or group, but do not select yourself. You can change this selection later.
   * Once the policy is active, this user or group's RBAC permissions will be further controlled for this specific Asset.
5. Set the attribute value for the selected user or group.
6. Click **Next** to review your changes.
7. Review the assignment summary, then click **Update** to confirm.

<Info>
  **No access**: At this point, no access has changed. The user still has the same RBAC role and permissions as before. Access will only change after you create a policy that references this attribute.
</Info>

## Step 2: Create and assign a resource attribute

### Create a resource attribute

1. In **Access Control**, click **Resource Attributes**.
2. Click **Create Resource Attribute**.
3. Configure the attribute [settings](/documentation/reference/manage/authorization-models-settings#attribute-data-types) and click **Save**.

### Assign a resource attribute

Assigning this attribute does not change access. It only labels the resource so that a policy can later reference this attribute.

1. In **Access Control**, click **Resource Attributes**.
2. In **Resource Attributes**, find the resource attribute to use.
3. Click <Icon icon="ellipsis-vertical" /> **Options**, then select **Assign**.
4. Select the resource type you want to manage: **Assets**, **Channels**, or **Runs**.
5. In the search field, enter the name of the resource to manage.
6. In the search results, select your resource.
7. Click **Update**.
8. Select a value for the attribute.
9. Click **Next**.
10. Review your changes, and then click **Update**.

## Step 3: Create a policy

1. In **Access Control**, click **Policies**.
2. Click **Create Policy**.
3. Configure the [policy settings](/documentation/reference/manage/authorization-models-settings#policy-settings) and click **Create**.

<Warning>
  **Implementation**: Creating the policy immediately grants or denies access.
</Warning>

## Next steps

* [Getting started with Data Access Governance (DAG)](/tutorials/manage/tutorial-3): A hands-on tutorial that walks through using DAG to protect a specific Asset by creating user and resource attributes and an explicit deny policy. By the end, you will have restricted a user's access to a sensitive Asset without changing their RBAC role.

## Reference

* [Authorization models settings](/documentation/reference/manage/authorization-models-settings)
