From a885caf59cedb62e7abef402e02b9242ed17840e Mon Sep 17 00:00:00 2001 From: Carter Brainerd Date: Wed, 11 Nov 2026 11:26:29 +0000 Subject: [PATCH 1/3] docs: Add new doc page `Setting Up Sourcegraph Securely` --- docs/admin/index.mdx | 1 + docs/admin/security.mdx | 115 ++++++++++++++++++++++++++++++++++++++++ src/data/navigation.ts | 4 ++ 3 files changed, 120 insertions(+) create mode 100644 docs/admin/security.mdx diff --git a/docs/admin/index.mdx b/docs/admin/index.mdx index 7be614203..a887dd53b 100644 --- a/docs/admin/index.mdx +++ b/docs/admin/index.mdx @@ -29,6 +29,7 @@ Sourcegraph administration is primarily managed by administrators, who are respo ## Configure Sourcegraph - [Administration Quickstart](/admin/how-to/site-admin-quickstart) +- [Setting up Sourcegraph securely](/admin/security) - [Advanced configuration](/admin/config/site-config) - [Global and user settings](/admin/config/settings) - [Configuring Authorization and Authentication](/admin/config/authorization-and-authentication) diff --git a/docs/admin/security.mdx b/docs/admin/security.mdx new file mode 100644 index 000000000..b3fbdef50 --- /dev/null +++ b/docs/admin/security.mdx @@ -0,0 +1,115 @@ +# Setting Up Sourcegraph Securely + + + Supported on [Enterprise](/pricing/plans/enterprise) plans. + + +This page lists the settings that strengthen the security posture of a Sourcegraph instance and what each one protects against. Work through it when you deploy a new instance, and review it after major changes to authentication, code hosts, or network topology. + +Most settings on this page are in the advanced configuration. See [how to view and edit the advanced configuration](/admin/config/site-config#view-and-edit-site-configuration), and the [advanced configuration reference](/admin/config/site-config#reference) for every setting's description and default. + + + On [Sourcegraph Cloud](/cloud/), Sourcegraph operates the deployment, so the + steps that involve the reverse proxy, environment variables, or the deployment + itself don't apply. The advanced configuration settings do. + + +## Before you expose the instance + +1. **Create the first administrator account right away.** The first account created on a new instance becomes a site administrator, whatever the sign-up settings are. Create it before the instance is reachable by anyone else. +2. **Serve Sourcegraph over HTTPS only.** Terminate TLS at the reverse proxy in front of Sourcegraph, redirect HTTP to HTTPS, and send an HSTS header. See [HTTP and HTTPS configuration](/self-hosted/http-https-configuration). +3. **Set `externalURL` to the `https://` URL of the instance**, such as `https://sourcegraph.example.com`. Sourcegraph sets the `Secure` attribute on its session cookie when `externalURL` uses `https`, so browsers never send the cookie over plain HTTP. + +## Control who can sign in + +1. **Use your identity provider.** Sign-in through [SAML](/admin/auth/saml/), [OpenID Connect](/admin/auth/#openid-connect), or your code host's OAuth applies your organization's MFA and offboarding to Sourcegraph. See [choosing an authentication provider](/admin/auth/#recommendations). +2. **Remove the `builtin` provider, or turn off self sign-up.** Once SSO works, remove `builtin` from `auth.providers` so that no local passwords exist. If you keep `builtin`, set `allowSignup` to `false` on it explicitly, so that administrators create every account. See [builtin password authentication](/admin/auth/builtin). +3. **Turn off account requests if you don't review them.** With sign-up off, the sign-in page lets anyone request an account unless `auth.accessRequest.enabled` is `false`. See [disable account requests](/admin/auth/builtin#disable-account-requests-from-users). +4. **Secure organization invitations.** Any member of an [organization](/admin/organizations) can invite other users to it. Invitations can't create accounts: they only add existing users. There is no setting that turns invitations off, so set `organizationInvitations.signingKey` to a random base64-encoded key, such as the output of `openssl rand -base64 32`. Without a key, Sourcegraph signs invitation links with an empty key, which doesn't protect them. +5. **Restrict sign-up through other providers too.** `allowSignup` on `builtin` doesn't apply to other providers. Set `allowSignup` on each provider, and limit code host OAuth to your organization, such as with `allowOrgs` for [GitHub](/admin/auth/#how-to-control-user-sign-up-and-sign-in-with-github-auth-provider) or `allowGroups` for [GitLab](/admin/auth/#how-to-control-user-sign-up-and-sign-in-with-gitlab-auth-provider). With github.com and open sign-up, anyone with a GitHub account can sign in. +6. **Require verified email addresses from OpenID Connect.** Sourcegraph links an OpenID Connect identity to the account with the same email address. Set `requireEmailVerified` to `true` on each `openidconnect` provider, so that Sourcegraph rejects a sign-in unless the provider returns `email_verified: true`, and no one can claim an email address they don't own. Microsoft Entra ID doesn't send the `email_verified` claim by default, so with this setting on, Entra ID users cannot sign in. For Entra ID, leave it off, or use [SAML](/admin/auth/saml/) instead. +7. **Deprovision users automatically.** [SCIM](/admin/scim) deactivates Sourcegraph users when they are removed in your identity provider. Use a long random value for `scim.authToken`, since it grants user management. +8. **Keep `auth.enableUsernameChanges` off** when you sync repository permissions or sign in with SSO. A user who renames their account could take a username that maps to another person's permissions. See [Authentication and authorization](/admin/config/authorization-and-authentication#authentication). + +### Strengthen local passwords + +If you keep the `builtin` provider: + +1. **Require strong passwords.** Raise `auth.minPasswordLength`, and enable `auth.passwordPolicy` to require numbers, mixed case, and special characters. +2. **Tune account lockout.** `auth.lockout` locks an account after repeated failed sign-in attempts. To let users unlock their account by email, set `auth.unlockAccountLinkSigningKey`. See [account lockout](/admin/auth/builtin#account-lockout). +3. **Keep password reset links short-lived** with `auth.passwordResetLinkExpiry`. + +## Limit sessions and tokens + +1. **Shorten sessions.** `auth.sessionExpiry` limits how long a session lasts, and `auth.maxSessionIdleDuration` signs out sessions that make no requests. Both accept Go durations of at least one hour: + + ```json + { + "auth.sessionExpiry": "168h", + "auth.maxSessionIdleDuration": "8h" + } + ``` + +2. **Restrict access tokens.** In `auth.accessTokens`, set `allow` to `site-admin-create` or `none` if regular users don't need tokens. Set `allowNoExpiration` to `false` explicitly, so that no one can create a token that never expires, and shorten `expirationOptionDays` and `defaultExpirationDays` to match your policy. See [managing access tokens](/cli/how-tos/managing-access-tokens). +3. **Require OAuth for the src CLI.** Set `srcCli.allowAccessTokenAuth` to `false` to reject access tokens sent by the src CLI, so that users sign in with [`src login`](/cli/quickstart#oauth-login) instead of storing a long-lived token. The src CLI is identified by its `User-Agent`, so treat this as a policy nudge, not a hard boundary. +4. **Use service accounts for automation.** Give CI and integrations a [service account](/admin/service-accounts) with only the roles it needs, instead of a person's token. +5. **Review OAuth apps.** Remove [OAuth apps](/admin/oauth-apps) that are no longer used. + +## Restrict network access + +### Allow only known IP addresses + +`auth.allowedIpAddress` rejects every request whose address is not on the allowlist. It runs before authentication, so it also covers the sign-in page and the API. + +```json +{ + "auth.allowedIpAddress": { + "enabled": true, + // Addresses that may open connections to Sourcegraph, such as your load balancer. + "clientIpAddress": ["10.0.0.0/24"], + // Addresses of end users, read from userIpRequestHeaders. + "userIpAddress": ["203.0.113.0/24"], + "userIpRequestHeaders": ["X-Forwarded-For"], + // Internal services that skip the user check, such as the Kubernetes pod range. + "trustedClientIpAddress": ["10.8.0.0/14"], + "errorMessageTemplate": "Access from {{.UserIP}} is not allowed. Contact your Sourcegraph administrator." + } +} +``` + +Before you enable it: + +1. **Include the addresses of Sourcegraph's own services** in `trustedClientIpAddress`, such as the pod range on Kubernetes, and the addresses of [executors](/admin/executors). Otherwise, services cannot reach the frontend. Sourcegraph always allows `127.0.0.1`. +2. **Only read the user address from a header your proxy controls.** Sourcegraph takes the first address in the first `userIpRequestHeaders` header that is present, and a client can send any value in that header. Configure your proxy to replace the header with the client's address, not append to it, and set `clientIpAddress` to the proxy's addresses so that clients cannot bypass it. +3. **Know how to recover.** If you block your own address, [edit the advanced configuration without the web UI](/admin/config/site-config#editing-your-site-configuration-if-you-cannot-access-the-web-ui). + +### Other network settings + +1. **Keep `corsOrigin` limited** to the origins of the code host integrations you use. Each origin listed can send cross-origin requests with users' cookies. +2. **Leave `auth.allowEmbeddedAuth` off** unless an internal application must embed the sign-in page. It protects the sign-in and sign-up pages from clickjacking. +3. **Filter outbound connections.** `EXTERNAL_DENY_LIST` and `UNTRUSTED_EXTERNAL_ALLOW_LIST` limit which hosts Sourcegraph and user-supplied URLs can reach. See [outgoing connection filtering](/self-hosted/network-filtering). +4. **Verify TLS to internal services.** Add your internal root CA to `tls.external.certificates` instead of setting `insecureSkipVerify`. See [trusting TLS certificates using internal PKI](/self-hosted/private-network#trusting-tls-certificates-using-internal-pki). + +## Protect code and data + +1. **Enforce repository permissions on every code host connection.** A new code host connection doesn't enforce repository permissions: every user can see every repository it syncs, including repositories that are private on the code host. Add `authorization` to each connection's configuration (`enforcePermissions` for Azure DevOps) and configure the matching authentication provider. See [getting started with repository permissions](/admin/permissions/#getting-started). +2. **Decide whether administrators bypass permissions.** By default, site administrators can see every repository. Set `authz.enforceForSiteAdmins` to `true` to apply repository permissions to them as well. See [administrators and repository permissions](/admin/permissions/#administrators). +3. **Grant features by role.** Use [access control](/admin/access-control/) to limit features such as Batch Changes to the users who need them. +4. **Encrypt secrets at rest.** `encryption.keys` encrypts code host tokens, user OAuth tokens, webhook secrets, executor secrets, and other sensitive database columns with a key in Cloud KMS, AWS KMS, or a mounted file. See [on-disk database encryption](/self-hosted/encryption). +5. **Keep sensitive code away from agents.** [Agent context filters](/context-filters) hide the repositories and files you list from the Deep Search and Agentic Batch Changes agents, so that they never reach a model provider. + +## Reduce the attack surface + +1. **Turn off features you don't use**, such as `deepSearch.enabled`, `batchChanges.enabled`, and `mcp.enabled`. When `mcp.enabled` is `false`, the MCP endpoints return 404. +2. **Limit MCP access.** Disable individual tools with `mcp.tools.disabled`. Once your MCP clients use pre-registered OAuth clients, [disable Dynamic Client Registration](/api/mcp/authentication#disable-dynamic-client-registration). +3. **Don't enable HTML injection.** The `htmlHeadTop`, `htmlHeadBottom`, `htmlBodyTop`, and `htmlBodyBottom` settings add raw HTML and scripts to every page, and take effect only when the `ENABLE_INJECT_HTML` environment variable is `true`. Leave that variable unset so that the advanced configuration cannot run scripts in users' browsers. +4. **Require proof of code host access for SCIP uploads.** With `lsifEnforceAuth` set to `true`, users without the upload permission must show a code host token with write access to the repository. See [indexing a Go repository](/code-navigation/how-to/index-a-go-repository) for the token the upload needs. +5. **Isolate executors.** Use a long random `executors.accessToken`, run jobs in [Firecracker](/admin/executors#sandboxing-model) where you can, and store credentials as [executor secrets](/admin/executors/executor-secrets). +6. **Restrict Batch Changes.** `batchChanges.containerRegistryAllowlist` limits which registries batch change steps pull images from, and `batchChanges.restrictMergeToAdmins` lets only site administrators merge changesets. +7. **Set a secret on every incoming webhook**, so that Sourcegraph rejects payloads the code host did not sign. See [incoming webhooks](/admin/webhooks/incoming). + +## Monitor the instance + +1. **Send audit logs to your SIEM.** The [audit log](/admin/audit-log) records authentication, user management, and configuration changes, and [security event logs](/admin/security-event-logs) record security-relevant actions. +2. **Review outbound requests.** The [outbound request log](/admin/outbound-request-log) shows the requests Sourcegraph makes to code hosts and other services. +3. **Stay up to date.** Security fixes ship in regular releases. See [updating Sourcegraph](/self-hosted/updates). diff --git a/src/data/navigation.ts b/src/data/navigation.ts index a4c5efff0..4aaad15f0 100644 --- a/src/data/navigation.ts +++ b/src/data/navigation.ts @@ -548,6 +548,10 @@ export const navigation: NavigationItem[] = [ href: '/admin/permissions' }, {title: 'OAuth apps', href: '/admin/oauth-apps'}, + { + title: 'Setting up Sourcegraph securely', + href: '/admin/security' + }, { title: 'Executors', href: '/admin/executors', From c29989c48f8a6419031b6ab494d7a8f45c90ff7f Mon Sep 17 00:00:00 2001 From: Carter Brainerd Date: Wed, 11 Nov 2026 11:28:38 +0000 Subject: [PATCH 2/3] cspell: Allow HMAC Amp-Thread-ID: https://ampcode.com/threads/T-01a1ca36-cb03-7754-9a95-4c97499c98aa Co-authored-by: Amp --- cspell-allow-list.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell-allow-list.txt b/cspell-allow-list.txt index 4ade45921..37ba630b8 100644 --- a/cspell-allow-list.txt +++ b/cspell-allow-list.txt @@ -242,6 +242,7 @@ gsuite healthcheck healthz HELO +HMAC horsegraph horsten hostmatcher From 33aa4feef5f1610cb595033eab433293817be19f Mon Sep 17 00:00:00 2001 From: Carter Brainerd Date: Wed, 11 Nov 2026 12:34:29 +0000 Subject: [PATCH 3/3] add self hosted badges --- docs/admin/security.mdx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/admin/security.mdx b/docs/admin/security.mdx index b3fbdef50..18e52123e 100644 --- a/docs/admin/security.mdx +++ b/docs/admin/security.mdx @@ -9,16 +9,16 @@ This page lists the settings that strengthen the security posture of a Sourcegra Most settings on this page are in the advanced configuration. See [how to view and edit the advanced configuration](/admin/config/site-config#view-and-edit-site-configuration), and the [advanced configuration reference](/admin/config/site-config#reference) for every setting's description and default. - On [Sourcegraph Cloud](/cloud/), Sourcegraph operates the deployment, so the - steps that involve the reverse proxy, environment variables, or the deployment - itself don't apply. The advanced configuration settings do. + Items tagged Self-hosted apply only to + self-hosted instances. On [Sourcegraph Cloud](/cloud/), Sourcegraph manages + them for you. ## Before you expose the instance -1. **Create the first administrator account right away.** The first account created on a new instance becomes a site administrator, whatever the sign-up settings are. Create it before the instance is reachable by anyone else. -2. **Serve Sourcegraph over HTTPS only.** Terminate TLS at the reverse proxy in front of Sourcegraph, redirect HTTP to HTTPS, and send an HSTS header. See [HTTP and HTTPS configuration](/self-hosted/http-https-configuration). -3. **Set `externalURL` to the `https://` URL of the instance**, such as `https://sourcegraph.example.com`. Sourcegraph sets the `Secure` attribute on its session cookie when `externalURL` uses `https`, so browsers never send the cookie over plain HTTP. +1. Self-hosted **Create the first administrator account before anyone else can reach the instance.** Until an account exists, every visitor sees the setup page, and the first account created there becomes a site administrator, whatever the sign-up settings are. Complete the setup page while the instance is reachable only by you. +2. Self-hosted **Serve Sourcegraph over HTTPS only.** Terminate TLS at the reverse proxy in front of Sourcegraph, redirect HTTP to HTTPS, and send an HSTS header. See [HTTP and HTTPS configuration](/self-hosted/http-https-configuration). +3. Self-hosted **Set `externalURL` to the `https://` URL of the instance**, such as `https://sourcegraph.example.com`. Sourcegraph sets the `Secure` attribute on its session cookie when `externalURL` uses `https`, so browsers never send the cookie over plain HTTP. ## Control who can sign in @@ -59,7 +59,7 @@ If you keep the `builtin` provider: ### Allow only known IP addresses -`auth.allowedIpAddress` rejects every request whose address is not on the allowlist. It runs before authentication, so it also covers the sign-in page and the API. +Self-hosted `auth.allowedIpAddress` rejects every request whose address is not on the allowlist. It runs before authentication, so it also covers the sign-in page and the API. ```json { @@ -87,7 +87,7 @@ Before you enable it: 1. **Keep `corsOrigin` limited** to the origins of the code host integrations you use. Each origin listed can send cross-origin requests with users' cookies. 2. **Leave `auth.allowEmbeddedAuth` off** unless an internal application must embed the sign-in page. It protects the sign-in and sign-up pages from clickjacking. -3. **Filter outbound connections.** `EXTERNAL_DENY_LIST` and `UNTRUSTED_EXTERNAL_ALLOW_LIST` limit which hosts Sourcegraph and user-supplied URLs can reach. See [outgoing connection filtering](/self-hosted/network-filtering). +3. Self-hosted **Filter outbound connections.** `EXTERNAL_DENY_LIST` and `UNTRUSTED_EXTERNAL_ALLOW_LIST` limit which hosts Sourcegraph and user-supplied URLs can reach. See [outgoing connection filtering](/self-hosted/network-filtering). 4. **Verify TLS to internal services.** Add your internal root CA to `tls.external.certificates` instead of setting `insecureSkipVerify`. See [trusting TLS certificates using internal PKI](/self-hosted/private-network#trusting-tls-certificates-using-internal-pki). ## Protect code and data @@ -95,14 +95,14 @@ Before you enable it: 1. **Enforce repository permissions on every code host connection.** A new code host connection doesn't enforce repository permissions: every user can see every repository it syncs, including repositories that are private on the code host. Add `authorization` to each connection's configuration (`enforcePermissions` for Azure DevOps) and configure the matching authentication provider. See [getting started with repository permissions](/admin/permissions/#getting-started). 2. **Decide whether administrators bypass permissions.** By default, site administrators can see every repository. Set `authz.enforceForSiteAdmins` to `true` to apply repository permissions to them as well. See [administrators and repository permissions](/admin/permissions/#administrators). 3. **Grant features by role.** Use [access control](/admin/access-control/) to limit features such as Batch Changes to the users who need them. -4. **Encrypt secrets at rest.** `encryption.keys` encrypts code host tokens, user OAuth tokens, webhook secrets, executor secrets, and other sensitive database columns with a key in Cloud KMS, AWS KMS, or a mounted file. See [on-disk database encryption](/self-hosted/encryption). +4. Self-hosted **Encrypt secrets at rest.** `encryption.keys` encrypts code host tokens, user OAuth tokens, webhook secrets, executor secrets, and other sensitive database columns with a key in Cloud KMS, AWS KMS, or a mounted file. See [on-disk database encryption](/self-hosted/encryption). 5. **Keep sensitive code away from agents.** [Agent context filters](/context-filters) hide the repositories and files you list from the Deep Search and Agentic Batch Changes agents, so that they never reach a model provider. ## Reduce the attack surface 1. **Turn off features you don't use**, such as `deepSearch.enabled`, `batchChanges.enabled`, and `mcp.enabled`. When `mcp.enabled` is `false`, the MCP endpoints return 404. 2. **Limit MCP access.** Disable individual tools with `mcp.tools.disabled`. Once your MCP clients use pre-registered OAuth clients, [disable Dynamic Client Registration](/api/mcp/authentication#disable-dynamic-client-registration). -3. **Don't enable HTML injection.** The `htmlHeadTop`, `htmlHeadBottom`, `htmlBodyTop`, and `htmlBodyBottom` settings add raw HTML and scripts to every page, and take effect only when the `ENABLE_INJECT_HTML` environment variable is `true`. Leave that variable unset so that the advanced configuration cannot run scripts in users' browsers. +3. Self-hosted **Don't enable HTML injection.** The `htmlHeadTop`, `htmlHeadBottom`, `htmlBodyTop`, and `htmlBodyBottom` settings add raw HTML and scripts to every page, and take effect only when the `ENABLE_INJECT_HTML` environment variable is `true`. Leave that variable unset so that the advanced configuration cannot run scripts in users' browsers. 4. **Require proof of code host access for SCIP uploads.** With `lsifEnforceAuth` set to `true`, users without the upload permission must show a code host token with write access to the repository. See [indexing a Go repository](/code-navigation/how-to/index-a-go-repository) for the token the upload needs. 5. **Isolate executors.** Use a long random `executors.accessToken`, run jobs in [Firecracker](/admin/executors#sandboxing-model) where you can, and store credentials as [executor secrets](/admin/executors/executor-secrets). 6. **Restrict Batch Changes.** `batchChanges.containerRegistryAllowlist` limits which registries batch change steps pull images from, and `batchChanges.restrictMergeToAdmins` lets only site administrators merge changesets. @@ -110,6 +110,6 @@ Before you enable it: ## Monitor the instance -1. **Send audit logs to your SIEM.** The [audit log](/admin/audit-log) records authentication, user management, and configuration changes, and [security event logs](/admin/security-event-logs) record security-relevant actions. +1. **Send audit logs to your SIEM.** The [audit log](/admin/audit-log) records authentication, user management, and configuration changes, and [security event logs](/admin/security-event-logs) record security-relevant actions. On Sourcegraph Cloud, see [Cloud audit logs](/cloud/#audit-logs). 2. **Review outbound requests.** The [outbound request log](/admin/outbound-request-log) shows the requests Sourcegraph makes to code hosts and other services. -3. **Stay up to date.** Security fixes ship in regular releases. See [updating Sourcegraph](/self-hosted/updates). +3. Self-hosted **Stay up to date.** Security fixes ship in regular releases. See [updating Sourcegraph](/self-hosted/updates).