From 83b545fc2340b2d90a192abb47cb9426a1f5eb84 Mon Sep 17 00:00:00 2001
From: Florian Greinacher <florian@greinacher.de>
Date: Fri, 12 Jan 2024 17:30:43 +0100
Subject: [PATCH] feat: add option to disable access to cloud metadata services
 (#26411)

---
 docs/usage/self-hosted-configuration.md |  6 ++++++
 lib/config/options/index.ts             |  8 ++++++++
 lib/config/types.ts                     |  1 +
 lib/workers/global/initialize.spec.ts   | 23 +++++++++++++++++++++++
 lib/workers/global/initialize.ts        | 11 +++++++++++
 5 files changed, 49 insertions(+)

diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md
index b1f62011d9..f57c95d91b 100644
--- a/docs/usage/self-hosted-configuration.md
+++ b/docs/usage/self-hosted-configuration.md
@@ -913,6 +913,12 @@ This is currently applicable to `npm` only, and only used in cases where bugs in
 If enabled emoji shortcodes are replaced with their Unicode equivalents.
 For example: `:warning:` will be replaced with `⚠️`.
 
+## useCloudMetadataServices
+
+Some cloud providers offer services to receive metadata about the current instance, for example [AWS Instance metadata](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-instance-metadata.html)
+or [GCP VM metadata](https://cloud.google.com/compute/docs/metadata/overview).
+Use this option to control whether Renovate should try to access these services.
+
 ## username
 
 You may need to set a `username` if you:
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index 1ec3b48136..ed4df4a415 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -21,6 +21,14 @@ const options: RenovateOptions[] = [
     default: false,
     globalOnly: true,
   },
+  {
+    name: 'useCloudMetadataServices',
+    description:
+      'If `false`, Renovate does not try to access cloud metadata services.',
+    type: 'boolean',
+    default: true,
+    globalOnly: true,
+  },
   {
     name: 'allowPostUpgradeCommandTemplating',
     description:
diff --git a/lib/config/types.ts b/lib/config/types.ts
index b8f0cceb1c..4ea506e975 100644
--- a/lib/config/types.ts
+++ b/lib/config/types.ts
@@ -117,6 +117,7 @@ export interface GlobalOnlyConfig {
   repositories?: RenovateRepository[];
   platform?: PlatformId;
   endpoint?: string;
+  useCloudMetadataServices?: boolean;
 }
 
 // Config options used within the repository worker, but not user configurable
diff --git a/lib/workers/global/initialize.spec.ts b/lib/workers/global/initialize.spec.ts
index 94297b1c10..2402e0e934 100644
--- a/lib/workers/global/initialize.spec.ts
+++ b/lib/workers/global/initialize.spec.ts
@@ -79,4 +79,27 @@ describe('workers/global/initialize', () => {
       await expect(globalInitialize(config)).toResolve();
     });
   });
+
+  describe('configureThirdPartyLibraries()', () => {
+    beforeEach(() => {
+      delete process.env.AWS_EC2_METADATA_DISABLED;
+      delete process.env.METADATA_SERVER_DETECTION;
+    });
+
+    it('sets env vars when cloud metadata services disabled', async () => {
+      const config: RenovateConfig = { useCloudMetadataServices: false };
+      git.validateGitVersion.mockResolvedValueOnce(true);
+      await expect(globalInitialize(config)).toResolve();
+      expect(process.env.AWS_EC2_METADATA_DISABLED).toBe('true');
+      expect(process.env.METADATA_SERVER_DETECTION).toBe('none');
+    });
+
+    it('does not set env vars when cloud metadata services enabled', async () => {
+      const config: RenovateConfig = { useCloudMetadataServices: true };
+      git.validateGitVersion.mockResolvedValueOnce(true);
+      await expect(globalInitialize(config)).toResolve();
+      expect(process.env.AWS_EC2_METADATA_DISABLED).toBeUndefined();
+      expect(process.env.METADATA_SERVER_DETECTION).toBeUndefined();
+    });
+  });
 });
diff --git a/lib/workers/global/initialize.ts b/lib/workers/global/initialize.ts
index 2773006bd1..41af7f9a5a 100644
--- a/lib/workers/global/initialize.ts
+++ b/lib/workers/global/initialize.ts
@@ -64,6 +64,16 @@ function setGlobalHostRules(config: RenovateConfig): void {
   }
 }
 
+function configureThirdPartyLibraries(config: AllConfig): void {
+  // Not using early return style to make clear what's the criterion to set the variables,
+  // especially when there is more stuff added here in the future.
+  if (!config.useCloudMetadataServices) {
+    logger.debug('Disabling the use of cloud metadata services');
+    process.env.AWS_EC2_METADATA_DISABLED = 'true'; // See https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html#envvars-list
+    process.env.METADATA_SERVER_DETECTION = 'none'; // See https://cloud.google.com/nodejs/docs/reference/gcp-metadata/latest#environment-variables
+  }
+}
+
 export async function globalInitialize(
   config_: AllConfig,
 ): Promise<RenovateConfig> {
@@ -76,6 +86,7 @@ export async function globalInitialize(
   limitCommitsPerRun(config);
   setEmojiConfig(config);
   setGlobalHostRules(config);
+  configureThirdPartyLibraries(config);
   await initMergeConfidence();
   return config;
 }
-- 
GitLab