Compare commits

...

14 Commits

Author SHA1 Message Date
bfc82105bd Merge pull request #1947 from Infisical/patch-multi-line-encoding
Patch multi line encoding when expandSecretRef is enabled
2024-06-11 00:55:31 -04:00
c8a3252c1a Merge pull request #1929 from Infisical/feat/add-option-to-mask-and-protect-gitlab-secrets
feat: add integration option to mask and protect gitlab secrets
2024-06-11 11:38:18 +08:00
0bba1801b9 Merge pull request #1936 from Infisical/daniel/go-sdk-docs
Docs: Go SDK
2024-06-11 04:27:17 +02:00
a61e92c49c Update go.mdx 2024-06-11 04:26:35 +02:00
9945d249d6 Merge pull request #1937 from Infisical/shubham/eng-487-investigate-the-stripedb-inconsistency
fix: update org seats whenever membership status is accepted
2024-06-11 07:05:27 +05:30
8329cbf299 update toggle lable 2024-06-10 17:09:20 -04:00
9138ab8ed7 update flag describe 2024-06-10 17:01:16 -04:00
aafddaa856 misc: finalized option label 2024-06-10 23:08:39 +08:00
776f464bee misc: used metadata schema parsing 2024-06-10 22:45:17 +08:00
104b0d6c60 Merge remote-tracking branch 'origin/main' into feat/add-option-to-mask-and-protect-gitlab-secrets 2024-06-10 22:41:44 +08:00
7c9c65312b fix: pass correct id 2024-06-10 09:04:34 +05:30
8a46cbd08f fix: update org seats whenever membership status is accepted 2024-06-10 09:02:11 +05:30
fa05639592 Docs: Go SDK 2024-06-10 05:18:39 +02:00
2bd9ad0137 feat: add option to maks and protect gitlab secrets 2024-06-07 21:46:34 +08:00
13 changed files with 507 additions and 13 deletions

View File

@ -77,7 +77,7 @@ type TLdapConfigServiceFactoryDep = {
>;
userAliasDAL: Pick<TUserAliasDALFactory, "create" | "findOne">;
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
licenseService: Pick<TLicenseServiceFactory, "getPlan" | "updateSubscriptionOrgMemberCount">;
};
export type TLdapConfigServiceFactory = ReturnType<typeof ldapConfigServiceFactory>;
@ -510,6 +510,7 @@ export const ldapConfigServiceFactory = ({
return newUserAlias;
});
}
await licenseService.updateSubscriptionOrgMemberCount(organization.id);
const user = await userDAL.transaction(async (tx) => {
const newUser = await userDAL.findOne({ id: userAlias.userId }, tx);

View File

@ -50,7 +50,7 @@ type TSamlConfigServiceFactoryDep = {
orgMembershipDAL: Pick<TOrgMembershipDALFactory, "create">;
orgBotDAL: Pick<TOrgBotDALFactory, "findOne" | "create" | "transaction">;
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
licenseService: Pick<TLicenseServiceFactory, "getPlan" | "updateSubscriptionOrgMemberCount">;
tokenService: Pick<TAuthTokenServiceFactory, "createTokenForUser">;
smtpService: Pick<TSmtpService, "sendMail">;
};
@ -449,6 +449,7 @@ export const samlConfigServiceFactory = ({
return newUser;
});
}
await licenseService.updateSubscriptionOrgMemberCount(organization.id);
const isUserCompleted = Boolean(user.isAccepted);
const providerAuthToken = jwt.sign(

View File

@ -391,7 +391,7 @@ export const scimServiceFactory = ({
);
}
}
await licenseService.updateSubscriptionOrgMemberCount(org.id);
return { user, orgMembership };
});

View File

@ -677,6 +677,8 @@ export const INTEGRATION = {
secretAWSTag: "The tags for AWS secrets.",
kmsKeyId: "The ID of the encryption key from AWS KMS.",
shouldDisableDelete: "The flag to disable deletion of secrets in AWS Parameter Store.",
shouldMaskSecrets: "Specifies if the secrets synced from Infisical to Gitlab should be marked as 'Masked'.",
shouldProtectSecrets: "Specifies if the secrets synced from Infisical to Gitlab should be marked as 'Protected'.",
shouldEnableDelete: "The flag to enable deletion of secrets"
}
},

View File

@ -1921,13 +1921,13 @@ const syncSecretsGitLab = async ({
return allEnvVariables;
};
const metadata = IntegrationMetadataSchema.parse(integration.metadata);
const allEnvVariables = await getAllEnvVariables(integration?.appId as string, accessToken);
const getSecretsRes: GitLabSecret[] = allEnvVariables
.filter((secret: GitLabSecret) => secret.environment_scope === integration.targetEnvironment)
.filter((gitLabSecret) => {
let isValid = true;
const metadata = z.record(z.any()).parse(integration.metadata);
if (metadata.secretPrefix && !gitLabSecret.key.startsWith(metadata.secretPrefix)) {
isValid = false;
}
@ -1947,8 +1947,8 @@ const syncSecretsGitLab = async ({
{
key,
value: secrets[key].value,
protected: false,
masked: false,
protected: Boolean(metadata.shouldProtectSecrets),
masked: Boolean(metadata.shouldMaskSecrets),
raw: false,
environment_scope: integration.targetEnvironment
},
@ -1965,7 +1965,9 @@ const syncSecretsGitLab = async ({
`${gitLabApiUrl}/v4/projects/${integration?.appId}/variables/${existingSecret.key}?filter[environment_scope]=${integration.targetEnvironment}`,
{
...existingSecret,
value: secrets[existingSecret.key].value
value: secrets[existingSecret.key].value,
protected: Boolean(metadata.shouldProtectSecrets),
masked: Boolean(metadata.shouldMaskSecrets)
},
{
headers: {

View File

@ -31,5 +31,7 @@ export const IntegrationMetadataSchema = z.object({
.describe(INTEGRATION.CREATE.metadata.secretAWSTag),
kmsKeyId: z.string().optional().describe(INTEGRATION.CREATE.metadata.kmsKeyId),
shouldDisableDelete: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.shouldDisableDelete),
shouldEnableDelete: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.shouldEnableDelete)
shouldEnableDelete: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.shouldEnableDelete),
shouldMaskSecrets: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.shouldMaskSecrets),
shouldProtectSecrets: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.shouldProtectSecrets)
});

View File

@ -29,6 +29,8 @@ export type TCreateIntegrationDTO = {
}[];
kmsKeyId?: string;
shouldDisableDelete?: boolean;
shouldMaskSecrets?: boolean;
shouldProtectSecrets?: boolean;
shouldEnableDelete?: boolean;
};
} & Omit<TProjectPermission, "projectId">;

View File

@ -315,6 +315,7 @@ export const orgServiceFactory = ({
},
tx
);
await licenseService.updateSubscriptionOrgMemberCount(org.id);
await orgBotDAL.create(
{
name: org.name,

View File

@ -1,4 +1,6 @@
/* eslint-disable no-await-in-loop */
import { AxiosError } from "axios";
import { getConfig } from "@app/lib/config/env";
import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto";
import { daysToMillisecond, secondsToMillis } from "@app/lib/dates";
@ -570,11 +572,14 @@ export const secretQueueFactory = ({
isSynced: true
});
} catch (err: unknown) {
logger.info("Secret integration sync error:", err);
logger.info("Secret integration sync error: %o", err);
const message =
err instanceof AxiosError ? JSON.stringify((err as AxiosError)?.response?.data) : (err as Error)?.message;
await integrationDAL.updateById(integration.id, {
lastSyncJobId: job.id,
lastUsed: new Date(),
syncMessage: (err as Error)?.message,
syncMessage: message,
isSynced: false
});
}

View File

@ -384,6 +384,7 @@
"pages": [
"sdks/languages/node",
"sdks/languages/python",
"sdks/languages/go",
"sdks/languages/java",
"sdks/languages/csharp"
]

438
docs/sdks/languages/go.mdx Normal file
View File

@ -0,0 +1,438 @@
---
title: "Infisical Go SDK"
sidebarTitle: "Go"
icon: "golang"
---
If you're working with Go Lang, the official [Infisical Go SDK](https://github.com/infisical/go-sdk) package is the easiest way to fetch and work with secrets for your application.
- [Package](https://pkg.go.dev/github.com/infisical/go-sdk)
- [Github Repository](https://github.com/infiscial/go-sdk)
## Basic Usage
```go
package main
import (
"fmt"
"os"
infisical "github.com/infisical/go-sdk"
)
func main() {
client, err := infisical.NewInfisicalClient(infisical.Config{
SiteUrl: "https://app.infisical.com", // Optional, default is https://app.infisical.com
})
if err != nil {
fmt.Printf("Error: %v", err)
os.Exit(1)
}
_, err = client.Auth().UniversalAuthLogin("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")
if err != nil {
fmt.Printf("Authentication failed: %v", err)
os.Exit(1)
}
apiKeySecret, err := client.Secrets().Retrieve(infisical.RetrieveSecretOptions{
SecretKey: "API_KEY",
Environment: "dev",
ProjectID: "YOUR_PROJECT_ID",
SecretPath: "/",
})
if err != nil {
fmt.Printf("Error: %v", err)
os.Exit(1)
}
fmt.Printf("API Key Secret: %v", apiKeySecret)
}
```
This example demonstrates how to use the Infisical Go SDK in a simple Go application. The application retrieves a secret named `API_KEY` from the `dev` environment of the `YOUR_PROJECT_ID` project.
<Warning>
We do not recommend hardcoding your [Machine Identity Tokens](/platform/identities/overview). Setting it as an environment variable would be best.
</Warning>
# Installation
```console
$ go get github.com/infisical/go-sdk
```
# Configuration
Import the SDK and create a client instance.
```go
client, err := infisical.NewInfisicalClient(infisical.Config{
SiteUrl: "https://app.infisical.com", // Optional, default is https://api.infisical.com
})
if err != nil {
fmt.Printf("Error: %v", err)
os.Exit(1)
}
```
### ClientSettings methods
<ParamField query="options" type="object">
<Expandable title="properties">
<ParamField query="SiteUrl" type="string" optional>
The URL of the Infisical API. Default is `https://api.infisical.com`.
</ParamField>
<ParamField query="UserAgent" type="string" required>
Optionally set the user agent that will be used for HTTP requests. _(Not recommended)_
</ParamField>
</Expandable>
</ParamField>
### Authentication
The SDK supports a variety of authentication methods. The most common authentication method is Universal Auth, which uses a client ID and client secret to authenticate.
#### Universal Auth
**Using environment variables**
Call `.Auth().UniversalAuthLogin()` with empty arguments to use the following environment variables:
- `INFISICAL_UNIVERSAL_AUTH_CLIENT_ID` - Your machine identity client ID.
- `INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET` - Your machine identity client secret.
**Using the SDK directly**
```go
_, err := client.Auth().UniversalAuthLogin("CLIENT_ID", "CLIENT_SECRET")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
```
#### GCP ID Token Auth
<Info>
Please note that this authentication method will only work if you're running your application on Google Cloud Platform.
Please [read more](/documentation/platform/identities/gcp-auth) about this authentication method.
</Info>
**Using environment variables**
Call `.Auth().GcpIdTokenAuthLogin()` with empty arguments to use the following environment variables:
- `INFISICAL_GCP_AUTH_IDENTITY_ID` - Your Infisical Machine Identity ID.
**Using the SDK directly**
```go
_, err := client.Auth().GcpIdTokenAuthLogin("YOUR_MACHINE_IDENTITY_ID")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
```
#### GCP IAM Auth
**Using environment variables**
Call `.Auth().GcpIamAuthLogin()` with empty arguments to use the following environment variables:
- `INFISICAL_GCP_IAM_AUTH_IDENTITY_ID` - Your Infisical Machine Identity ID.
- `INFISICAL_GCP_IAM_SERVICE_ACCOUNT_KEY_FILE_PATH` - The path to your GCP service account key file.
**Using the SDK directly**
```go
_, err = client.Auth().GcpIamAuthLogin("MACHINE_IDENTITY_ID", "SERVICE_ACCOUNT_KEY_FILE_PATH")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
```
#### AWS IAM Auth
<Info>
Please note that this authentication method will only work if you're running your application on AWS.
Please [read more](/documentation/platform/identities/aws-auth) about this authentication method.
</Info>
**Using environment variables**
Call `.Auth().AwsIamAuthLogin()` with empty arguments to use the following environment variables:
- `INFISICAL_AWS_IAM_AUTH_IDENTITY_ID` - Your Infisical Machine Identity ID.
**Using the SDK directly**
```go
_, err = client.Auth().AwsIamAuthLogin("MACHINE_IDENTITY_ID")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
```
#### Azure Auth
<Info>
Please note that this authentication method will only work if you're running your application on Azure.
Please [read more](/documentation/platform/identities/azure-auth) about this authentication method.
</Info>
**Using environment variables**
Call `.Auth().AzureAuthLogin()` with empty arguments to use the following environment variables:
- `INFISICAL_AZURE_AUTH_IDENTITY_ID` - Your Infisical Machine Identity ID.
**Using the SDK directly**
```go
_, err = client.Auth().AzureAuthLogin("MACHINE_IDENTITY_ID")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
```
#### Kubernetes Auth
<Info>
Please note that this authentication method will only work if you're running your application on Kubernetes.
Please [read more](/documentation/platform/identities/kubernetes-auth) about this authentication method.
</Info>
**Using environment variables**
Call `.Auth().KubernetesAuthLogin()` with empty arguments to use the following environment variables:
- `INFISICAL_KUBERNETES_IDENTITY_ID` - Your Infisical Machine Identity ID.
- `INFISICAL_KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH_ENV_NAME` - The environment variable name that contains the path to the service account token. This is optional and will default to `/var/run/secrets/kubernetes.io/serviceaccount/token`.
**Using the SDK directly**
```go
// Service account token path will default to /var/run/secrets/kubernetes.io/serviceaccount/token if empty value is passed
_, err = client.Auth().KubernetesAuthLogin("MACHINE_IDENTITY_ID", "SERVICE_ACCOUNT_TOKEN_PATH")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
```
## Working with Secrets
### client.Secrets().List(options)
```go
secrets, err := client.Secrets().List(infisical.ListSecretsOptions{
ProjectID: "PROJECT_ID",
Environment: "dev",
SecretPath: "/foo/bar",
AttachToProcessEnv: false,
})
```
Retrieve all secrets within the Infisical project and environment that client is connected to
#### Parameters
<ParamField query="Parameters" type="object">
<Expandable title="properties">
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="ProjectID" type="string">
The project ID where the secret lives in.
</ParamField>
<ParamField query="SecretPath" type="string" optional>
The path from where secrets should be fetched from.
</ParamField>
<ParamField query="AttachToProcessEnv" type="boolean" default="false" optional>
Whether or not to set the fetched secrets to the process environment. If true, you can access the secrets like so `System.getenv("SECRET_NAME")`.
</ParamField>
<ParamField query="IncludeImports" type="boolean" default="false" optional>
Whether or not to include imported secrets from the current path. Read about [secret import](/documentation/platform/secret-reference)
</ParamField>
<ParamField query="Recursive" type="boolean" default="false" optional>
Whether or not to fetch secrets recursively from the specified path. Please note that there's a 20-depth limit for recursive fetching.
</ParamField>
<ParamField query="ExpandSecretReferences" type="boolean" default="true" optional>
Whether or not to expand secret references in the fetched secrets. Read about [secret reference](/documentation/platform/secret-reference)
</ParamField>
</Expandable>
</ParamField>
### client.Secrets().Get(options)
```go
secret, err := client.Secrets().Retrieve(infisical.RetrieveSecretOptions{
SecretKey: "API_KEY",
ProjectID: "PROJECT_ID",
Environment: "dev",
})
```
Retrieve a secret from Infisical.
By default, `Secrets().Get()` fetches and returns a shared secret.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="SecretKey" type="string" required>
The key of the secret to retrieve.
</ParamField>
<ParamField query="ProjectID" type="string" required>
The project ID where the secret lives in.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="SecretPath" type="string" optional>
The path from where secret should be fetched from.
</ParamField>
<ParamField query="Type" type="string" optional>
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
</ParamField>
</Expandable>
</ParamField>
### client.Secrets().Create(options)
```go
secret, err := client.Secrets().Create(infisical.CreateSecretOptions{
ProjectID: "PROJECT_ID",
Environment: "dev",
SecretKey: "NEW_SECRET_KEY",
SecretValue: "NEW_SECRET_VALUE",
SecretComment: "This is a new secret",
})
```
Create a new secret in Infisical.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="SecretKey" type="string" required>
The key of the secret to create.
</ParamField>
<ParamField query="SecretValue" type="string" required>
The value of the secret.
</ParamField>
<ParamField query="SecretComment" type="string" optional>
A comment for the secret.
</ParamField>
<ParamField query="ProjectID" type="string" required>
The project ID where the secret lives in.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="SecretPath" type="string" optional>
The path from where secret should be created.
</ParamField>
<ParamField query="Type" type="string" optional>
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
</ParamField>
</Expandable>
</ParamField>
### client.Secrets().Update(options)
```go
secret, err := client.Secrets().Update(infisical.UpdateSecretOptions{
ProjectID: "PROJECT_ID",
Environment: "dev",
SecretKey: "NEW_SECRET_KEY",
NewSecretValue: "NEW_SECRET_VALUE",
NewSkipMultilineEncoding: false,
})
```
Update an existing secret in Infisical.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="SecretKey" type="string" required>
The key of the secret to update.
</ParamField>
<ParamField query="NewSecretValue" type="string" required>
The new value of the secret.
</ParamField>
<ParamField query="NewSkipMultilineEncoding" type="boolean" default="false" optional>
Whether or not to skip multiline encoding for the new secret value.
</ParamField>
<ParamField query="ProjectID" type="string" required>
The project ID where the secret lives in.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="SecretPath" type="string" optional>
The path from where secret should be updated.
</ParamField>
<ParamField query="Type" type="string" optional>
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
</ParamField>
</Expandable>
</ParamField>
### client.Secrets().Delete(options)
```go
secret, err := client.Secrets().Delete(infisical.DeleteSecretOptions{
ProjectID: "PROJECT_ID",
Environment: "dev",
SecretKey: "SECRET_KEY",
})
```
Delete a secret in Infisical.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="SecretKey" type="string">
The key of the secret to update.
</ParamField>
<ParamField query="ProjectID" type="string" required>
The project ID where the secret lives in.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where secrets should be fetched from.
</ParamField>
<ParamField query="SecretPath" type="string" optional>
The path from where secret should be deleted.
</ParamField>
<ParamField query="Type" type="string" optional>
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
</ParamField>
</Expandable>
</ParamField>

View File

@ -73,6 +73,8 @@ export const useCreateIntegration = () => {
}[];
kmsKeyId?: string;
shouldDisableDelete?: boolean;
shouldMaskSecrets?: boolean;
shouldProtectSecrets?: boolean;
shouldEnableDelete?: boolean;
};
}) => {

View File

@ -25,6 +25,7 @@ import {
ModalContent,
Select,
SelectItem,
Switch,
Tab,
TabList,
TabPanel,
@ -58,7 +59,9 @@ const schema = yup.object({
targetAppId: yup.string().required("GitLab project is required"),
targetEnvironment: yup.string(),
secretPrefix: yup.string(),
secretSuffix: yup.string()
secretSuffix: yup.string(),
shouldMaskSecrets: yup.boolean(),
shouldProtectSecrets: yup.boolean()
});
type FormData = yup.InferType<typeof schema>;
@ -138,7 +141,9 @@ export default function GitLabCreateIntegrationPage() {
targetAppId,
targetEnvironment,
secretPrefix,
secretSuffix
secretSuffix,
shouldMaskSecrets,
shouldProtectSecrets
}: FormData) => {
try {
setIsLoading(true);
@ -156,7 +161,9 @@ export default function GitLabCreateIntegrationPage() {
secretPath,
metadata: {
secretPrefix,
secretSuffix
secretSuffix,
shouldMaskSecrets,
shouldProtectSecrets
}
});
@ -390,6 +397,36 @@ export default function GitLabCreateIntegrationPage() {
exit={{ opacity: 0, translateX: 30 }}
className="pb-[14.25rem]"
>
<div className="ml-1">
<Controller
control={control}
name="shouldMaskSecrets"
render={({ field: { onChange, value } }) => (
<Switch
id="should-mask-secrets"
onCheckedChange={(isChecked) => onChange(isChecked)}
isChecked={value}
>
<div className="max-w-md">Mark Infisical secrets in Gitlab as &apos;Masked&apos; secrets</div>
</Switch>
)}
/>
</div>
<div className="ml-1 mt-4 mb-5">
<Controller
control={control}
name="shouldProtectSecrets"
render={({ field: { onChange, value } }) => (
<Switch
id="should-protect-secrets"
onCheckedChange={(isChecked) => onChange(isChecked)}
isChecked={value}
>
Mark Infisical secrets in Gitlab as &apos;Protected&apos; secrets
</Switch>
)}
/>
</div>
<Controller
control={control}
name="secretPrefix"