Compare commits

...

14 Commits

Author SHA1 Message Date
Scott Wilson
ba94b91974 Merge pull request #3510 from Infisical/internal-ip-check-fix
fix(external-connections): Use Hostname for Blocking Internal IPs DNS Resolve
2025-04-29 12:37:46 -07:00
Scott Wilson
b65f62fda8 fix: use hostname for blocking internal IPs 2025-04-29 12:26:29 -07:00
x032205
9138a9e71d Merge pull request #3509 from Infisical/feat/teamcity-ignore-inherited-secrets
feat(secret-sync): TeamCity ignore inherited and non-env values
2025-04-29 12:49:01 -04:00
x
8e4ad8baf8 docs tweak 2025-04-29 12:43:44 -04:00
x
9f158d5b3f feat(docs): Added note stating that inherited secrets are ignored 2025-04-29 10:35:56 -04:00
x
0e1cb4ebb2 Merge branch 'main' into feat/teamcity-ignore-inherited-secrets 2025-04-29 10:31:51 -04:00
Maidul Islam
8f07f43fbd Merge pull request #3504 from akhilmhdh/doc/assume-privilege
doc: added doc for assume privilege feature
2025-04-28 20:08:44 -07:00
Maidul Islam
023f5d1286 revise docs 2025-04-28 23:06:37 -04:00
Daniel Hougaard
72b03d4bdf Merge pull request #3506 from Infisical/daniel/build-strict-find-filter
feat: strict find filter
2025-04-29 05:41:39 +04:00
Daniel Hougaard
e870e35002 consolidated filtering functions into one 2025-04-29 04:27:10 +04:00
x
ddb5098eda only sync non-inherited environment variables 2025-04-28 19:09:13 -04:00
Daniel Hougaard
85965184f8 Update secret-v2-bridge-dal.ts 2025-04-29 00:18:13 +04:00
Daniel Hougaard
a1bbd50c0b feat: build strict find filter 2025-04-29 00:09:30 +04:00
=
6bca854475 doc: added doc for assume privilege feature 2025-04-29 00:12:37 +05:30
10 changed files with 84 additions and 18 deletions

View File

@@ -2,6 +2,8 @@
import { Knex } from "knex";
import { Tables } from "knex/types/tables";
import { TableName } from "@app/db/schemas";
import { DatabaseError } from "../errors";
import { buildDynamicKnexQuery, TKnexDynamicOperator } from "./dynamic";
@@ -25,28 +27,41 @@ export type TFindFilter<R extends object = object> = Partial<R> & {
$search?: Partial<{ [k in keyof R]: R[k] }>;
$complex?: TKnexDynamicOperator<R>;
};
export const buildFindFilter =
<R extends object = object>({ $in, $notNull, $search, $complex, ...filter }: TFindFilter<R>) =>
<R extends object = object>(
{ $in, $notNull, $search, $complex, ...filter }: TFindFilter<R>,
tableName?: TableName,
excludeKeys?: Array<keyof R>
) =>
(bd: Knex.QueryBuilder<R, R>) => {
void bd.where(filter);
const processedFilter = tableName
? Object.fromEntries(
Object.entries(filter)
.filter(([key]) => !excludeKeys || !excludeKeys.includes(key as keyof R))
.map(([key, value]) => [`${tableName}.${key}`, value])
)
: filter;
void bd.where(processedFilter);
if ($in) {
Object.entries($in).forEach(([key, val]) => {
if (val) {
void bd.whereIn(key as never, val as never);
void bd.whereIn([`${tableName ? `${tableName}.` : ""}${key}`] as never, val as never);
}
});
}
if ($notNull?.length) {
$notNull.forEach((key) => {
void bd.whereNotNull(key as never);
void bd.whereNotNull([`${tableName ? `${tableName}.` : ""}${key as string}`] as never);
});
}
if ($search) {
Object.entries($search).forEach(([key, val]) => {
if (val) {
void bd.whereILike(key as never, val as never);
void bd.whereILike([`${tableName ? `${tableName}.` : ""}${key}`] as never, val as never);
}
});
}

View File

@@ -15,13 +15,13 @@ export const blockLocalAndPrivateIpAddresses = async (url: string) => {
const validUrl = new URL(url);
const inputHostIps: string[] = [];
if (isIPv4(validUrl.host)) {
inputHostIps.push(validUrl.host);
if (isIPv4(validUrl.hostname)) {
inputHostIps.push(validUrl.hostname);
} else {
if (validUrl.host === "localhost" || validUrl.host === "host.docker.internal") {
if (validUrl.hostname === "localhost" || validUrl.hostname === "host.docker.internal") {
throw new BadRequestError({ message: "Local IPs not allowed as URL" });
}
const resolvedIps = await dns.resolve4(validUrl.host);
const resolvedIps = await dns.resolve4(validUrl.hostname);
inputHostIps.push(...resolvedIps);
}
const isInternalIp = inputHostIps.some((el) => isPrivateIp(el));

View File

@@ -10,7 +10,7 @@ import {
TTeamCitySyncWithCredentials
} from "@app/services/secret-sync/teamcity/teamcity-sync-types";
// Note: Most variables won't be returned with a value due to them being a "password" type (starting with "env.").
// Note: Most variables won't be returned with a value due to them being a "password" type.
// TeamCity API returns empty string for password-type variables for security reasons.
const listTeamCityVariables = async ({ instanceUrl, accessToken, project, buildConfig }: TTeamCityListVariables) => {
const { data } = await request.get<TTeamCityListVariablesResponse>(
@@ -25,12 +25,16 @@ const listTeamCityVariables = async ({ instanceUrl, accessToken, project, buildC
}
);
// Filters for only non-inherited environment variables
// Strips out "env." from map key, but the "name" field still has the original unaltered key.
return Object.fromEntries(
data.property.map((variable) => [
variable.name.startsWith("env.") ? variable.name.substring(4) : variable.name,
{ ...variable, value: variable.value || "" } // Password values will be empty strings from the API for security
])
data.property
.filter((variable) => !variable.inherited)
.filter((variable) => variable.name.startsWith("env."))
.map((variable) => [
variable.name.substring(4),
{ ...variable, value: variable.value || "" } // Password values will be empty strings from the API for security
])
);
};

View File

@@ -64,7 +64,8 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => {
const findOne = async (filter: Partial<TSecretsV2>, tx?: Knex) => {
try {
const docs = await (tx || db)(TableName.SecretV2)
.where(filter)
// eslint-disable-next-line @typescript-eslint/no-misused-promises
.where(buildFindFilter(filter, TableName.SecretV2))
.leftJoin(
TableName.SecretV2JnTag,
`${TableName.SecretV2}.id`,

View File

@@ -0,0 +1,40 @@
---
title: "Assume Privileges"
description: "Learn how to temporarily assume the privileges of a user or machine identity within a project."
---
This feature allows authorized users to temporarily take on the permissions of another user or identity. It helps administrators and access managers test and verify permissions before granting access, ensuring everything is set up correctly.
It also reduces back-and-forth with end users when troubleshooting permission-related issues.
## How It Works
When an authorized user activates assume privileges mode, they temporarily inherit the target user or identitys permissions for up to one hour.
During this time, they can perform actions within the system with the same level of access as the target user.
- **Permission-based**: Only permissions are inherited, not the full identity
- **Time-limited**: Access automatically expires after one hour
- **Audited**: All actions are logged under the original user's account. This means any action taken during the session will be recorded under the entity assuming the privileges, not the target entity.
- **Authorization required**: Only users with the specific **assume privilege** permission can use this feature
- **Scoped to a single project**: You can only assume privileges for one project at a time
## How to Assume Privileges
<Steps>
<Step title="Go to Project Access">
Click on the user or identity you want to assume.
![Access control page](/images/platform/access-controls/assume-privileges/access-control.png)
</Step>
<Step title="Click Assume Privilege">
Click **Assume Privilege**, then type `assume` to confirm and start your session.
![Access control detail page](/images/platform/access-controls/assume-privileges/access-control-detail.png)
</Step>
<Step title="Session is Active">
You will see a yellow banner indicating that your assume privilege session is active. You can exit at any time by clicking **Exit**.
![session start](/images/platform/access-controls/assume-privileges/session-start.png)
</Step>
</Steps>

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

View File

@@ -34,7 +34,7 @@ description: "Learn how to configure a TeamCity Sync for Infisical."
- **Build Configuration**: The build configuration to sync secrets to.
<Note>
Not including a Build Configuration will sync secrets to the entire project.
Not including a Build Configuration will sync secrets to the project.
</Note>
5. Configure the **Sync Options** to specify how secrets should be synced, then click **Next**.
@@ -44,6 +44,11 @@ description: "Learn how to configure a TeamCity Sync for Infisical."
- **Overwrite Destination Secrets**: Removes any secrets at the destination endpoint not present in Infisical.
- **Import Secrets (Prioritize Infisical)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Infisical over TeamCity when keys conflict.
- **Import Secrets (Prioritize TeamCity)**: Imports secrets from the destination endpoint before syncing, prioritizing values from TeamCity over Infisical when keys conflict.
<Note>
Infisical only syncs secrets from within the target scope; inherited secrets will not be imported.
</Note>
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.

View File

@@ -160,6 +160,7 @@
},
"documentation/platform/access-controls/additional-privileges",
"documentation/platform/access-controls/temporary-access",
"documentation/platform/access-controls/assume-privilege",
"documentation/platform/access-controls/access-requests",
"documentation/platform/access-controls/project-access-requests",
"documentation/platform/pr-workflows",
@@ -887,8 +888,8 @@
]
},
{
"group": "LDAP Password",
"pages": [
"group": "LDAP Password",
"pages": [
"api-reference/endpoints/secret-rotations/ldap-password/create",
"api-reference/endpoints/secret-rotations/ldap-password/delete",
"api-reference/endpoints/secret-rotations/ldap-password/get-by-id",