Skip to content

fix: support custom-host for azure plugin to support privatelink #1117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

b4s36t4
Copy link
Contributor

@b4s36t4 b4s36t4 commented May 30, 2025

Description

CustomHost support for azure plugin to use with azure private-link

Motivation

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)

How Has This Been Tested?

  • Unit Tests
  • Integration Tests
  • Manual Testing

Screenshots (if applicable)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Related Issues

Copy link

matter-code-review bot commented May 30, 2025

Code Quality security vulnerability new feature

Description

Summary By MatterAI MatterAI logo

🔄 What Changed

This pull request introduces support for custom hostnames in the Azure plugin, primarily to facilitate integration with Azure Private Link endpoints. The changes involve:

  • Modifying URL construction in contentSafety.ts and pii.ts to use credentials.customHost if provided, falling back to the default Azure cognitive services domain.
  • Importing and utilizing https.Agent to disable SSL certificate validation (rejectUnauthorized: false) when a customHost is used. This is explicitly noted as a security consideration for private link scenarios.
  • Updating plugins/azure/manifest.json to include customHost as a configurable parameter for the Azure plugin.
  • Adding customHost?: string; to the AzureCredentials interface in plugins/azure/types.ts for type safety.
  • Expanding the PostOptions interface in plugins/utils.ts with an index signature [key: string]: any; to allow passing the dispatcher (the https.Agent) to the post function.

🔍 Impact of the Change

This change enables users to connect to Azure AI services via private endpoints (like Private Link), which often use custom hostnames and may not have publicly trusted SSL certificates. The primary impact is enhanced connectivity options for secure, private network deployments. However, the disabling of SSL certificate validation introduces a potential security risk that users must be aware of and manage carefully.

📁 Total Files Changed

5 files changed.

🧪 Test Added

N/A - The PR description does not explicitly mention new tests. It is recommended to add unit or integration tests to verify the custom host URL construction and the correct application of the dispatcher with rejectUnauthorized: false.

🔒Security Vulnerabilities

Potential Security Vulnerability Detected: The implementation disables SSL certificate validation (rejectUnauthorized: false) when customHost is used. While justified for Azure Private Link's self-signed certificates, this practice can expose the application to Man-in-the-Middle (MITM) attacks if the customHost is not a trusted, controlled endpoint. It is crucial that customHost values are rigorously validated and sourced only from trusted configurations.

Motivation

Support custom-host for azure plugin to support privatelink

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)

How Has This Been Tested?

  • Unit Tests
  • Integration Tests
  • Manual Testing

Screenshots (if applicable)

N/A

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Related Issues

.

Tip

Quality Recommendations

  1. The use of rejectUnauthorized: false for custom hosts, while necessary for some Private Link setups, introduces a significant security risk (Man-in-the-Middle attacks) if the customHost is not strictly controlled and validated. It is highly recommended to implement a robust mechanism to ensure that customHost values are only from a trusted, pre-approved list or configuration. Consider adding a clear warning in the plugin's configuration documentation about this security implication.

  2. For improved type safety in plugins/utils.ts, instead of the broad [key: string]: any; in PostOptions, consider defining a more specific type for dispatcher if it's primarily intended for https.Agent or similar dispatchers. For example, dispatcher?: Agent | Dispatcher; if Dispatcher is a known type from the underlying HTTP client library.

Sequence Diagram

sequenceDiagram
    actor User
    participant PluginHandler as Azure Plugin Handler (contentSafety/pii)
    participant Credentials as Azure Credentials
    participant AccessTokenService as getAccessToken()
    participant HttpsAgent as https.Agent
    participant PostFunction as post()
    participant AzureAIService as Azure AI Service Endpoint

    User->>PluginHandler: Invoke Azure Plugin (parameters, credentials)
    PluginHandler->>Credentials: Read customHost and resourceName
    alt customHost provided
        PluginHandler->>PluginHandler: Construct URL using customHost
        PluginHandler->>HttpsAgent: Create new Agent({ rejectUnauthorized: false })
        PluginHandler-->>HttpsAgent: Agent instance created
    else customHost not provided
        PluginHandler->>PluginHandler: Construct URL using resourceName
        PluginHandler-->>HttpsAgent: Agent remains null
    end
    PluginHandler->>AccessTokenService: Request Access Token (credentials)
    AccessTokenService-->>PluginHandler: Return token (or error)
    PluginHandler->>PostFunction: Call post(url, requestBody, { headers, dispatcher: agent }, timeout)
    PostFunction->>HttpsAgent: Use dispatcher (Agent) for request (if provided)
    PostFunction->>AzureAIService: Send HTTP POST Request (url, requestBody)
    AzureAIService-->>PostFunction: Return API Response
    PostFunction-->>PluginHandler: Return Response
    PluginHandler-->>User: Return Plugin Verdict and Data
Loading

Copy link

@matter-code-review matter-code-review bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds support for custom hosts in Azure plugins, which is valuable for private link scenarios. The implementation is generally good, but I've identified a few security and code quality improvements that should be addressed.

Skipped files
  • package-lock.json: Skipped file pattern
  • package.json: Skipped file pattern

Comment on lines 84 to 92
let agent: Agent | null = null;
// privatelink doesn't contain a valid certificate, skipping verification if it's customHost.
if (credentials.customHost) {
agent = new Agent({
connect: {
rejectUnauthorized: false,
},
});
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security Issue Fix

Issue: The code unconditionally disables SSL verification for all custom hosts, which could create security vulnerabilities if used with untrusted endpoints.
Fix: Add a more explicit comment about the security implications and consider making this configurable.
Impact: Improves security awareness and gives users more control over the security tradeoffs.

Suggested change
let agent: Agent | null = null;
// privatelink doesn't contain a valid certificate, skipping verification if it's customHost.
if (credentials.customHost) {
agent = new Agent({
connect: {
rejectUnauthorized: false,
},
});
}
let agent: Agent | null = null;
// SECURITY NOTE: The following disables SSL certificate validation for custom hosts.
// This is necessary for Azure Private Link endpoints that may use self-signed certificates,
// but should only be used with trusted private endpoints.
if (credentials.customHost) {
agent = new Agent({
connect: {
rejectUnauthorized: false,
},
});
}

Comment on lines 57 to 65
let agent: Agent | null = null;
// privatelink doesn't contain a valid certificate, skipping verification if it's customHost.
if (credentials?.customHost) {
agent = new Agent({
connect: {
rejectUnauthorized: false,
},
});
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security Issue Fix

Issue: The code unconditionally disables SSL verification for all custom hosts, which could create security vulnerabilities if used with untrusted endpoints.
Fix: Add a more explicit comment about the security implications and consider making this configurable.
Impact: Improves security awareness and gives users more control over the security tradeoffs.

Suggested change
let agent: Agent | null = null;
// privatelink doesn't contain a valid certificate, skipping verification if it's customHost.
if (credentials?.customHost) {
agent = new Agent({
connect: {
rejectUnauthorized: false,
},
});
}
let agent: Agent | null = null;
// SECURITY NOTE: The following disables SSL certificate validation for custom hosts.
// This is necessary for Azure Private Link endpoints that may use self-signed certificates,
// but should only be used with trusted private endpoints.
if (credentials?.customHost) {
agent = new Agent({
connect: {
rejectUnauthorized: false,
},
});
}

@@ -63,7 +64,7 @@ export const handler: PluginHandler<{

const apiVersion = parameters.apiVersion || '2024-11-01';

const url = `https://${credentials.resourceName}.cognitiveservices.azure.com/contentsafety/text:analyze?api-version=${apiVersion}`;
const url = `${credentials.customHost || `https://${credentials.resourceName}.cognitiveservices.azure.com`}/contentsafety/text:analyze?api-version=${apiVersion}`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Code Refactor

Issue: The URL construction doesn't validate if the customHost is a valid URL format.
Fix: Add a simple validation to ensure the customHost is properly formatted.
Impact: Prevents runtime errors from malformed URLs.

Suggested change
const url = `${credentials.customHost || `https://${credentials.resourceName}.cognitiveservices.azure.com`}/contentsafety/text:analyze?api-version=${apiVersion}`;
const baseUrl = credentials.customHost || `https://${credentials.resourceName}.cognitiveservices.azure.com`;
// Ensure the URL doesn't have trailing slashes that could cause path issues
const normalizedBaseUrl = baseUrl.replace(/\\/+$/, '');
const url = `${normalizedBaseUrl}/contentsafety/text:analyze?api-version=${apiVersion}`;

@@ -29,7 +30,7 @@ const redact = async (

const apiVersion = parameters.apiVersion || '2024-11-01';

const url = `https://${credentials?.resourceName}.cognitiveservices.azure.com/language/:analyze-text?api-version=${apiVersion}`;
const url = `${credentials?.customHost || `https://${credentials?.resourceName}.cognitiveservices.azure.com`}/language/:analyze-text?api-version=${apiVersion}`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Code Refactor

Issue: The URL construction doesn't validate if the customHost is a valid URL format.
Fix: Add a simple validation to ensure the customHost is properly formatted.
Impact: Prevents runtime errors from malformed URLs.

Suggested change
const url = `${credentials?.customHost || `https://${credentials?.resourceName}.cognitiveservices.azure.com`}/language/:analyze-text?api-version=${apiVersion}`;
const baseUrl = credentials?.customHost || `https://${credentials?.resourceName}.cognitiveservices.azure.com`;
// Ensure the URL doesn't have trailing slashes that could cause path issues
const normalizedBaseUrl = baseUrl.replace(/\\/+$/, '');
const url = `${normalizedBaseUrl}/language/:analyze-text?api-version=${apiVersion}`;

Comment on lines +127 to +129
"customHost": {
"type": "string",
"description": "Custom host for Azure AI services (Private Link etc.)"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Documentation Improvement

Issue: The description for customHost doesn't mention the security implications of using this feature.
Fix: Enhance the description to include security considerations.
Impact: Improves user awareness of security implications when using custom hosts.

Suggested change
"customHost": {
"type": "string",
"description": "Custom host for Azure AI services (Private Link etc.)"
\"customHost\": {
\"type\": \"string\",
\"description\": \"Custom host for Azure AI services (Private Link etc.). Note: SSL verification is disabled when using custom hosts.\"

Copy link

Important

PR Review Skipped

PR review skipped as per the configuration setting. Run a manually review by commenting /matter review

💡Tips to use Matter AI

Command List

  • /matter summary: Generate AI Summary for the PR
  • /matter review: Generate AI Reviews for the latest commit in the PR
  • /matter review-full: Generate AI Reviews for the complete PR
  • /matter release-notes: Generate AI release-notes for the PR
  • /matter : Chat with your PR with Matter AI Agent
  • /matter remember : Generate AI memories for the PR
  • /matter explain: Get an explanation of the PR
  • /matter help: Show the list of available commands and documentation
  • Need help? Join our Discord server: https://discord.gg/fJU5DvanU3

@b4s36t4 b4s36t4 force-pushed the fix/azure-plugin-custom-host branch from 5f6d0b6 to 83493d9 Compare May 30, 2025 13:02
Copy link

Important

PR Review Skipped

PR review skipped as per the configuration setting. Run a manually review by commenting /matter review

💡Tips to use Matter AI

Command List

  • /matter summary: Generate AI Summary for the PR
  • /matter review: Generate AI Reviews for the latest commit in the PR
  • /matter review-full: Generate AI Reviews for the complete PR
  • /matter release-notes: Generate AI release-notes for the PR
  • /matter : Chat with your PR with Matter AI Agent
  • /matter remember : Generate AI memories for the PR
  • /matter explain: Get an explanation of the PR
  • /matter help: Show the list of available commands and documentation
  • Need help? Join our Discord server: https://discord.gg/fJU5DvanU3

Copy link
Collaborator

@narengogi narengogi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor comment, but looks good

@@ -53,8 +54,24 @@ const redact = async (
throw new Error('Unable to get access token');
}

let agent: Agent | null = null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would suggest moving the initialization to a fetchUtils file and creating a method like getInsecureAgent()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants