From d84bac5fba25cc9ecab34b3539799e80685e6e80 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 26 Feb 2025 20:43:59 +0530 Subject: [PATCH] feat: changes based on reviews --- backend/src/ee/routes/v1/gateway-router.ts | 2 +- .../ee/services/gateway/gateway-service.ts | 7 +-- backend/src/lib/gateway/index.ts | 8 +++- cli/packages/gateway/gateway.go | 44 ++++++++++++------- .../platform/gateways/overview.mdx | 27 ++++++------ .../GatewayListPage/GatewayListPage.tsx | 6 +-- 6 files changed, 55 insertions(+), 39 deletions(-) diff --git a/backend/src/ee/routes/v1/gateway-router.ts b/backend/src/ee/routes/v1/gateway-router.ts index ea3e1f6d6..c916e229e 100644 --- a/backend/src/ee/routes/v1/gateway-router.ts +++ b/backend/src/ee/routes/v1/gateway-router.ts @@ -37,7 +37,7 @@ export const registerGatewayRouter = async (server: FastifyZodProvider) => { turnServerPassword: z.string(), turnServerRealm: z.string(), turnServerAddress: z.string(), - infisicalStaticIp: z.string() + infisicalStaticIp: z.string().optional() }) } }, diff --git a/backend/src/ee/services/gateway/gateway-service.ts b/backend/src/ee/services/gateway/gateway-service.ts index 10314335b..fdfaa8ab1 100644 --- a/backend/src/ee/services/gateway/gateway-service.ts +++ b/backend/src/ee/services/gateway/gateway-service.ts @@ -97,12 +97,7 @@ export const gatewayServiceFactory = ({ orgId: actorOrgId }); - if ( - !envCfg.GATEWAY_RELAY_AUTH_SECRET || - !envCfg.GATEWAY_RELAY_ADDRESS || - !envCfg.GATEWAY_INFISICAL_STATIC_IP_ADDRESS || - !envCfg.GATEWAY_RELAY_REALM - ) { + if (!envCfg.GATEWAY_RELAY_AUTH_SECRET || !envCfg.GATEWAY_RELAY_ADDRESS || !envCfg.GATEWAY_RELAY_REALM) { throw new BadRequestError({ message: "Gateway handshake failed due to missing instance configuration." }); diff --git a/backend/src/lib/gateway/index.ts b/backend/src/lib/gateway/index.ts index 4cb3e87b8..eaebd896d 100644 --- a/backend/src/lib/gateway/index.ts +++ b/backend/src/lib/gateway/index.ts @@ -105,7 +105,10 @@ export const pingGatewayAndVerify = async ({ } } - throw new Error(`Failed to ping gateway after ${maxRetries} attempts. Last error: ${lastError?.message}`); + logger.error(lastError); + throw new BadRequestError({ + message: `Failed to ping gateway after ${maxRetries} attempts. Last error: ${lastError?.message}` + }); }; interface TProxyServer { @@ -251,6 +254,9 @@ export const withGatewayProxy = async ( try { // Execute the callback with the allocated port await callback(port); + } catch (err) { + logger.error(err, "Failed to proxy"); + throw new BadRequestError({ message: (err as Error)?.message }); } finally { // Ensure cleanup happens regardless of success or failure cleanup(); diff --git a/cli/packages/gateway/gateway.go b/cli/packages/gateway/gateway.go index 658d1fef8..e5ec03293 100644 --- a/cli/packages/gateway/gateway.go +++ b/cli/packages/gateway/gateway.go @@ -49,14 +49,25 @@ func (g *Gateway) ConnectWithRelay() error { if err != nil { return err } - - turnServerAddr, err := net.ResolveTCPAddr("tcp", relayDetails.TurnServerAddress) - if err != nil { - return fmt.Errorf("Failed to resolve TURN server address: %w", err) - } + relayAddress, relayPort := strings.Split(relayDetails.TurnServerAddress, ":")[0], strings.Split(relayDetails.TurnServerAddress, ":")[1] + var conn net.Conn // Dial TURN Server - conn, err := net.DialTCP("tcp", nil, turnServerAddr) + if relayPort == "5349" { + log.Info().Msgf("Provided relay port %s. Using TLS", relayPort) + conn, err = tls.Dial("tcp", relayDetails.TurnServerAddress, &tls.Config{ + InsecureSkipVerify: false, + ServerName: relayAddress, + }) + } else { + log.Info().Msgf("Provided relay port %s. Using non TLS connection.", relayPort) + peerAddr, err := net.ResolveTCPAddr("tcp", relayDetails.TurnServerAddress) + if err != nil { + return fmt.Errorf("Failed to parse turn server address: %w", err) + } + conn, err = net.DialTCP("tcp", nil, peerAddr) + } + if err != nil { return fmt.Errorf("Failed to connect with relay server: %w", err) } @@ -85,7 +96,7 @@ func (g *Gateway) ConnectWithRelay() error { InfisicalStaticIp: relayDetails.InfisicalStaticIp, } // if port not specific allow all port - if !strings.Contains(relayDetails.InfisicalStaticIp, ":") { + if relayDetails.InfisicalStaticIp != "" && !strings.Contains(relayDetails.InfisicalStaticIp, ":") { g.config.InfisicalStaticIp = g.config.InfisicalStaticIp + ":0" } @@ -116,10 +127,6 @@ func (g *Gateway) Listen(ctx context.Context) error { } }() - peerAddr, err := net.ResolveTCPAddr("tcp", g.config.InfisicalStaticIp) - if err != nil { - return fmt.Errorf("Failed to parse infisical static ip: %w", err) - } gatewayCert, err := api.CallExchangeRelayCertV1(g.httpClient, api.ExchangeRelayCertRequestV1{ RelayAddress: relayNonTlsConn.Addr().String(), }) @@ -134,10 +141,17 @@ func (g *Gateway) Listen(ctx context.Context) error { done := make(chan bool, 1) - g.registerPermissionLifecycle(func() error { - err := relayNonTlsConn.CreatePermissions(peerAddr) - return err - }, done) + if g.config.InfisicalStaticIp != "" { + log.Info().Msgf("Found static ip from Infisical: %s. Creating permission IP lifecycle", g.config.InfisicalStaticIp) + peerAddr, err := net.ResolveTCPAddr("tcp", g.config.InfisicalStaticIp) + if err != nil { + return fmt.Errorf("Failed to parse infisical static ip: %w", err) + } + g.registerPermissionLifecycle(func() error { + err := relayNonTlsConn.CreatePermissions(peerAddr) + return err + }, done) + } cert, err := tls.X509KeyPair([]byte(gatewayCert.Certificate), []byte(gatewayCert.PrivateKey)) if err != nil { diff --git a/docs/documentation/platform/gateways/overview.mdx b/docs/documentation/platform/gateways/overview.mdx index 1dfde2784..d263dc278 100644 --- a/docs/documentation/platform/gateways/overview.mdx +++ b/docs/documentation/platform/gateways/overview.mdx @@ -1,7 +1,7 @@ --- title: "Gateway" sidebarTitle: "Overview" -description: "How access private network resources from Infisical" +description: "How to access private network resources from Infisical" --- The Infisical Gateway provides secure access to private resources within your network without needing direct inbound connections to your environment. @@ -9,28 +9,29 @@ This method keeps your resources fully protected from external access while enab Common use cases include generating dynamic credentials or rotating credentials for private databases. - **Note:** Gateway is a paid feature. - - - **Infisical Cloud users:** Gateway is available under the **Enterprise Tier**. - - **Self-Hosted Infisical:** Please contact [sales@infisical.com](mailto:sales@infisical.com) to purchase an enterprise license. + **Note:** Gateway is a paid feature. - **Infisical Cloud users:** Gateway is + available under the **Enterprise Tier**. - **Self-Hosted Infisical:** Please + contact [sales@infisical.com](mailto:sales@infisical.com) to purchase an + enterprise license. ## How It Works -The Gateway serves as a secure intermediary that facilitates direct communication between the Infisical server and your private network. +The Gateway serves as a secure intermediary that facilitates direct communication between the Infisical server and your private network. It’s a lightweight daemon packaged within the Infisical CLI, making it easy to deploy and manage. Once set up, the Gateway establishes a connection with a relay server, ensuring that all communication between Infisical and your Gateway is fully end-to-end encrypted. This setup guarantees that only the platform and your Gateway can decrypt the transmitted information, keeping communication with your resources secure, private and isolated. - ## Deployment -The Infisical Gateway is seamlessly integrated into the Infisical CLI under the `gateway` command, making it simple to deploy and manage. -You can install the Gateway in all the same ways you install the Infisical CLI—whether via npm, Docker, or a binary. + +The Infisical Gateway is seamlessly integrated into the Infisical CLI under the `gateway` command, making it simple to deploy and manage. +You can install the Gateway in all the same ways you install the Infisical CLI—whether via npm, Docker, or a binary. For detailed installation instructions, refer to the Infisical [CLI Installation instructions](/cli/overview). -To function, the Gateway must authenticate with Infisical. This requires a machine identity configured with the appropriate permissions to create and manage a Gateway. -Once authenticated, the Gateway establishes a secure connection with Infisical to allow your private resources to be reachable. +To function, the Gateway must authenticate with Infisical. This requires a machine identity configured with the appropriate permissions to create and manage a Gateway. +Once authenticated, the Gateway establishes a secure connection with Infisical to allow your private resources to be reachable. ### Deployment process + 1. Navigate to **Organization Access Control** in your Infisical dashboard. @@ -67,7 +68,6 @@ Once authenticated, the Gateway establishes a secure connection with Infisical t ![Gateway List](../../../images/platform/gateways/gateway-list.png) - To enable Infisical features like dynamic secrets or secret rotation to access private resources through the Gateway, you need to link the Gateway to the relevant projects. @@ -77,4 +77,5 @@ Once authenticated, the Gateway establishes a secure connection with Infisical t ![Project Assignment Modal](../../../images/platform/gateways/assign-project.png) Once added to a project, the Gateway becomes available for use by any feature that supports Gateways within that project. - \ No newline at end of file + + diff --git a/frontend/src/pages/organization/Gateways/GatewayListPage/GatewayListPage.tsx b/frontend/src/pages/organization/Gateways/GatewayListPage/GatewayListPage.tsx index d2bf32a55..85ec82334 100644 --- a/frontend/src/pages/organization/Gateways/GatewayListPage/GatewayListPage.tsx +++ b/frontend/src/pages/organization/Gateways/GatewayListPage/GatewayListPage.tsx @@ -94,7 +94,7 @@ export const GatewayListPage = withPermission( Gateways @@ -109,7 +109,7 @@ export const GatewayListPage = withPermission( } - description="Create and configure connections with third-party apps for re-use across Infisical projects" + description="Create and configure gateway to access private network resources from Infisical" />
@@ -118,7 +118,7 @@ export const GatewayListPage = withPermission( value={search} onChange={(e) => setSearch(e.target.value)} leftIcon={} - placeholder="Search connections..." + placeholder="Search gateway..." className="flex-1" />