diff --git a/baton/aws.mdx b/baton/aws.mdx index cb321b2a..b0d15d50 100644 --- a/baton/aws.mdx +++ b/baton/aws.mdx @@ -73,6 +73,34 @@ session will be issued directly or through role chaining; C1 must derive that topology from its configured issuance mode and apply the corresponding AWS limit. +## AWS STS federation token action + +The connector also exposes the global `issue_federation_token` action, which +calls AWS STS `GetFederationToken` to mint temporary credentials for a named +federated session. The credentials are returned as encrypted secret data; the +federated user ARN and ID, the session token size, and the session token +utilization are returned as ordinary fields. + +The action accepts: + +- `name`: the federated session name, 2 through 32 characters from + `[A-Za-z0-9_+=,.@-]`. It is a label for the session, not a lookup of an + existing IAM or Identity Center user; +- `duration_seconds`: optional, 900 through 129,600 (AWS defaults to 43,200); +- `policy`: an optional inline session policy, as JSON; +- `policy_arns`: up to 10 managed policy ARNs from the calling IAM user's own + account; +- `tags`: optional session tags, up to 50 key/value pairs; and +- `minimum_session_token_size`: optional, 0 through 4,096 bytes. + +Two constraints are worth calling out. First, `GetFederationToken` must be +signed with long-term IAM user keys: a connector running on assumed-role or +other temporary credentials cannot use this action, and the calling identity +needs `sts:GetFederationToken`. Second, the issued credentials get no +permissions at all unless you pass `policy` or `policy_arns` — the session's +access is the intersection of the IAM user's permissions and the policies +supplied here. + ## Cloud infrastructure access: Organizations and permission sets as scoped bindings When both **Enable support for AWS Organizations** and **Enable support for AWS IAM Identity Center** are turned on, the connector also models Identity Center permission set assignments as **Cloud Infrastructure Access** bindings, alongside the existing flat per-account entitlement model. This introduces four resource types: diff --git a/baton/azure-devops.mdx b/baton/azure-devops.mdx index 02ff8291..d99ae4c0 100644 --- a/baton/azure-devops.mdx +++ b/baton/azure-devops.mdx @@ -79,6 +79,24 @@ calls the Azure DevOps Identities API and requires `vso.identity` in addition to the `vso.auditlog` scope required by incremental sync. +## Team administrators + +When **Sync teams** is enabled, each team has an **admin** entitlement that shows everyone Azure DevOps lists as a team administrator. This includes users, groups, and service principals, even if they aren't members of the team. When a group is a team administrator, its members also appear as team administrators in C1. + +Administrators who have access only because they are Project Administrators or Project Collection Administrators are not listed, since Azure DevOps doesn't show them as team administrators either. + +To read team administrators, the connector needs access to the team's security settings: + +- **Client secret:** no extra setup. The service principal is a Project Collection Administrator. +- **OAuth:** add the `vso.security_manage` and `vso.identity` permissions. +- **Personal access token:** add the **Security: Manage** and **Identity: Read** scopes. + +If the connector can't read the team's security settings, the sync still completes. In that case, only team administrators who are also team members are shown. + + +Team administrators can't be granted or revoked from C1. Manage them in Azure DevOps. Changes to team administrators are picked up on the next full sync, not by incremental sync. + + ## Gather Azure DevOps credentials Configuring the connector requires you to pass in credentials generated in Azure DevOps. Gather these credentials before you move on. diff --git a/baton/bridge-client.mdx b/baton/bridge-client.mdx index fcade5a9..92e7f857 100644 --- a/baton/bridge-client.mdx +++ b/baton/bridge-client.mdx @@ -255,6 +255,14 @@ For each scalar above, a sibling `C1_BRIDGE_SECRET_` env var accepts a `" `ca_pem` has no scalar form (`C1_BRIDGE_CA_PEM` doesn't exist) — multi-line PEM data doesn't round-trip cleanly through shell envs, so it lives in YAML or comes from a secret backend. +### macOS certificate trust + +On macOS, the bridge uses the macOS certificate trust store by default. If `SSL_CERT_FILE` or `SSL_CERT_DIR` is set, it uses the specified CA bundle or directory instead for connections that rely on system roots, including authentication, gateway, and Vault secret backend connections. + +The bridge's `ca_path` and `ca_pem` add certificates to these roots rather than replacing them, so `SSL_CERT_FILE` and `SSL_CERT_DIR` still affect authentication and gateway connections. For the Vault connection, `VAULT_CACERT`, `VAULT_CACERT_BYTES`, or `VAULT_CAPATH` take precedence over system roots. + +To use the macOS trust store, unset both variables. If other tools require them, set `GODEBUG=x509sslcertoverrideplatform=0` when running the bridge to use macOS certificate verification while leaving those variables set. + ### Single-service env mode For deployments that don't want to ship a YAML config at all, a single service mapping can be defined entirely in the environment. When both `C1_BRIDGE_SERVICE_LISTEN_PORT` and `C1_BRIDGE_SERVICE_BACKEND` are set, a single port is constructed from the `C1_BRIDGE_SERVICE_*` vars and **replaces** any `ports:` block loaded from YAML. diff --git a/baton/cloudflare-zero-trust.mdx b/baton/cloudflare-zero-trust.mdx index ad0e0d2b..b2022804 100644 --- a/baton/cloudflare-zero-trust.mdx +++ b/baton/cloudflare-zero-trust.mdx @@ -14,6 +14,124 @@ sidebarTitle: "Cloudflare Zero Trust" | Access groups | | | | Roles | | | +## Access group rules + +Cloudflare Access groups grant membership using three rule lists with +different logic: + +- **Include** — OR. A user matches the group if at least one rule matches. +- **Require** — AND. A user must also match every rule in this list. +- **Exclude** — NOT. A user must not match any rule in this list. + +Each list can contain several rule types (email, email domain, everyone, +country, IP range, IdP group claim, a nested Access group, etc.). This +connector can evaluate some of them and not others, and rules it cannot +evaluate are **skipped** rather than treated as non-matching: + +| Rule type | Evaluated? | Effect on reported membership | +| :--- | :--- | :--- | +| `email`, `email_domain`, `everyone` | Yes | Fully enforced in all three lists. | +| `group` (nested Access group) | In `Include` only | Reported as an expandable grant — see below. | +| `ip`, `ip_list`, `geo`, `certificate`, `device_posture`, `auth_method`, `login_method`, `auth_context`, `external_evaluation` | No | None, by design. | +| `email_list`, IdP group claims (`okta`, `gsuite`, `saml`, ...), service tokens | No | May over- or under-report — see below. | + +### Why skipped rules do not narrow membership + +Each list combines its rules with a boolean operator, and a skipped rule is +treated as that operator's neutral element so it cannot change the list's +answer: satisfied under `Require`'s AND, non-matching under `Include`'s OR +and `Exclude`'s NOT. + +This matters most for `Require`. If a skipped rule were treated as "does not +match", a single one would make the whole AND fail and the group would report +**no members at all**. A group with `Include: email` and `Require: geo US` +really does grant access to that user, and C1 reports it. + + +**A group whose `Include` list contains nothing this connector can evaluate +reports no members at all.** `Include` is an OR, and its neutral element is +"no match", so a list made up entirely of skipped rules — an IdP-group claim +on its own, for example, which is a common Access setup — produces an empty +result. + +That direction under-reports rather than over-reports, and an empty group in +an access review reads as "nobody has access" rather than "this could not be +determined". The connector cannot tell the difference, and inventing members +would be worse, so it logs every group in this state at sync time and lists +the group's rules on its resource profile. Check those groups in Cloudflare +directly. + + +Contextual rules — country, IP range, mTLS certificate, device posture, +authentication method — are never evaluated, and this is deliberate rather +than a gap. They constrain *the request*: where it comes from and how it +authenticated. They do not change *who* the policy grants access to, and +Cloudflare evaluates them per request, so no connector can resolve them at +sync time. C1 models who a policy grants access to, not the conditions under +which that access applies. + + +**Rules that name identities this connector cannot read may cause C1 to +over-report membership.** Nested Access groups referenced from +`Require`/`Exclude`, email lists, IdP group claims (`okta`, `gsuite`, +`saml`) and service tokens all name real identities, but in a directory +this connector does not sync. + +Because they are skipped, a user who does not satisfy a `Require` rule — or +who should be removed by an `Exclude` rule — may still be reported as a +member of the group. In `Include` the effect runs the other way: a member +admitted only by such a rule is not reported at all. Every group carrying such a rule is logged at sync +time, and its rules are listed on the group's profile in C1 under +`include_rules` / `require_rules` / `exclude_rules`, so you can see exactly +which conditions were not applied. + +For those groups, confirm membership in Cloudflare before relying on C1 for +an access review. + + +A nested Access group referenced in **Include** is represented as an +expandable grant on the referenced group's own membership — so nested +group membership (including further nesting) is reflected in C1 without +this connector re-evaluating every member on every sync. + + +**Nested Include membership is not reported when the same group also has +`Require` or `Exclude` rules that this connector can evaluate.** An +expandable grant is a union: it pulls in everyone who holds the nested +group's membership, and the outer group's `Require`/`Exclude` rules cannot +be applied to the members it pulls in. A member excluded by the outer group +would otherwise still be reported as a member of it. + +Rather than over-report access, the connector omits the nested membership +for those groups and reports only the members matched directly by the outer +group's own `email`, `email_domain` and `everyone` rules. Rules that are +skipped anyway — and a `Require` list consisting only of `everyone` — are +not treated as restrictions, since they filter nothing. Affected groups are +logged at sync time. + + +### Granting and revoking group membership + +C1 adds a member to an Access group by appending an `email` rule to the +group's `Include` list, and removes one by deleting that rule. Everything +else about the group — its name and its `Require` and `Exclude` rules — is +written back unchanged. + +Because membership is expressed as rules rather than as a member list, some +requests cannot be carried out, and the connector refuses them rather than +reporting a change it did not make: + +| Request | Result | +| :--- | :--- | +| Grant to someone a `Require` or `Exclude` rule keeps out | **Refused.** The rule would be written but would grant nothing, and C1 would never hold the grant, so the rule would stay in your policy unnoticed. | +| Grant to someone already admitted by a broad rule (`everyone`, `email_domain`) | **No change.** They already have access, and adding a rule naming them would only leave a redundant one behind. | +| Revoke from someone whose access comes from a broad rule | **Refused.** That rule governs other members too, so it cannot be edited on one person's behalf. Change it in Cloudflare instead. | +| Revoke the last `email` rule in a group's `Include` list | **Refused.** Cloudflare rejects a group with an empty `Include` list. Delete or edit the group in Cloudflare instead. | +| Revoke from someone who is not a member | **No change.** | + +Membership that comes from a nested Access group cannot be revoked here +either: the member belongs to the referenced group, not to this one. + ## Gather Cloudflare Zero Trust credentials Configuring the connector requires you to pass in credentials generated in Cloudflare Zero Trust. Gather these credentials before you move on. @@ -68,11 +186,13 @@ A user with **Super Administrator** access in Cloudflare Zero Trust must perform - Account -> Access: Organizations, Identity Providers, and Groups -> Edit - Account -> Access: Apps and Policies -> Read - Account -> Access: Audit Logs -> Read + - Account -> Memberships -> Edit Otherwise, set: - Account -> Account Settings -> Read - Account -> Access: Organizations, Identity Providers, and Groups -> Read + - Account -> Memberships -> Read - Account -> Access: Apps and Policies -> Read - Account -> Access: Audit Logs -> Read diff --git a/baton/coupa.mdx b/baton/coupa.mdx index d792eda9..19381edf 100644 --- a/baton/coupa.mdx +++ b/baton/coupa.mdx @@ -35,11 +35,25 @@ C1 can create Coupa user accounts. When you configure account provisioning for t | Last name | Last name of the person who will own the Coupa user. | | Email | Email address of the Coupa user. Defaults to the C1 user's primary email. | | Login | Login for the Coupa user. Defaults to the C1 user's username. | +| SSO identifier | Single sign-on identifier for the Coupa user. | +| Employee number | Employee number for the Coupa user. | +| Manager login | Login of the user's manager in Coupa. | +| Purchasing user | Assign a Purchasing license when the account is created. | +| Invoicing user | Assign an Invoicing license when the account is created. | +| Sourcing user | Assign a Sourcing license when the account is created. | +| Account security type | Numeric Coupa account security type. | +| Authentication method | `coupa_credentials`, `ldap`, or `saml`; values are case-sensitive. | +| Default locale | Default locale, such as `en` or `en-GB`. | +| Default account type | Name of the user's default Coupa account type. | +| Default currency | ISO currency code, such as `USD`. | +| Custom fields | Map of instance-specific Coupa user field names to values. | Every field is optional to C1. Map **First name** and **Last name** regardless — Coupa has no other source for a new user's name. Accounts are created active. Coupa authenticates through SSO, so no password is set. +Custom fields are sent in Coupa's `custom-fields` namespace. License assignments can also be managed after account creation through C1 License Management. + ### Connector actions Connector actions are custom capabilities that extend C1 automations with app-specific operations. You can use connector actions in the [Perform connector action](/product/admin/automations-steps-reference#perform-connector-action) automation step. diff --git a/baton/databricks.mdx b/baton/databricks.mdx index bfc4d0cc..7e61eccb 100644 --- a/baton/databricks.mdx +++ b/baton/databricks.mdx @@ -29,12 +29,6 @@ Provisioning **account groups** requires OAuth authentication. It is not availab The connector authenticates with **OAuth** — an account-level service principal's client ID and secret. This is the only method currently offered. - -**Workspace-token (personal access token) authentication is temporarily unavailable.** It is not offered when configuring the connector, and configurations that specify it are rejected at startup. Use OAuth instead. - -The connector's PAT implementation is intact and the method is expected to return; it is withheld while a platform-side defect is resolved. The defect is not in this connector: a credential declared as a list of secrets is not treated as secret by the configuration layer, so a workspace token supplied through the UI would be stored unencrypted and displayed in clear text. - - ## Gather Databricks credentials Configuring the connector requires you to pass in credentials generated in Databricks. Gather these credentials before you move on. @@ -78,10 +72,6 @@ The Databricks connector authenticates with OAuth: - OAuth client ID - OAuth client secret - -Personal access token (workspace token) authentication is **temporarily unavailable** and is not offered when configuring the connector, so there is no need to generate one. See [Authentication methods](#authentication-methods) above. - - Next, move on to the instructions for your chosen setup method. ## Configure the Databricks connector @@ -214,25 +204,16 @@ stringData: BATON_DATABRICKS_CLIENT_ID: BATON_DATABRICKS_CLIENT_SECRET: - # Optional: limit the sync to specific workspaces, by deployment name. - # Mutually exclusive with BATON_DATABRICKS_EXCLUDE_WORKSPACES — set one or the other, never both. - # BATON_WORKSPACES: - # Optional: exclude specific workspaces from the sync # (workspace name, deployment name, or numeric ID). - # Mutually exclusive with BATON_WORKSPACES — set one or the other, never both. BATON_DATABRICKS_EXCLUDE_WORKSPACES: # Optional: include if you want C1 to provision access using this connector BATON_PROVISIONING: true ``` - -**`BATON_WORKSPACES` and `BATON_DATABRICKS_EXCLUDE_WORKSPACES` cannot both be set.** They are mutually exclusive, and a config carrying both is rejected at startup before any API call. Choose one. - - -OAuth requires a reachable account API. If the account API check fails at startup, the connector fails validation instead of falling back to a workspace-only sync, even when `BATON_WORKSPACES` is set. +OAuth requires a reachable account API. If the account API check fails at startup, the connector fails validation instead of falling back to a workspace-only sync. See the connector's README or run `--help` to see all available configuration flags and environment variables. diff --git a/baton/google-identity-platform.mdx b/baton/google-identity-platform.mdx index a26a9f1f..b678cf25 100644 --- a/baton/google-identity-platform.mdx +++ b/baton/google-identity-platform.mdx @@ -35,7 +35,7 @@ In the toolbar, click the project select dropdown, and click **NEW PROJECT**. Create a new project for your organization: - - **Project Name**: Choose a names, such as "C1 Integration" + - **Project Name**: Choose a name, such as "C1 Integration" - **Organization/Location**: Choose the appropriate Organization/Location