Skip to content

Commit

Permalink
feat: Check BIOS for GCE residency on Linux.
Browse files Browse the repository at this point in the history
  • Loading branch information
amanda-tarafa committed Oct 27, 2023
1 parent 0ac3f1c commit c3ada0f
Showing 1 changed file with 84 additions and 4 deletions.
88 changes: 84 additions & 4 deletions Src/Support/Google.Apis.Auth/OAuth2/ComputeCredential.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ limitations under the License.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -46,8 +48,7 @@ public class ComputeCredential : ServiceCredential, IOidcTokenProvider, IGoogleC
public const string MetadataServerUrl = GoogleAuthConsts.DefaultMetadataServerUrl;

/// <summary>Caches result from first call to <c>IsRunningOnComputeEngine</c> </summary>
private readonly static Lazy<Task<bool>> isRunningOnComputeEngineCached = new Lazy<Task<bool>>(
() => IsRunningOnComputeEngineNoCache());
private readonly static Lazy<Task<bool>> isRunningOnComputeEngineCached = new Lazy<Task<bool>>(IsRunningOnComputeEngineNoCacheAsync);

/// <summary>
/// Originally 1000ms was used without a retry. This proved inadequate; even 2000ms without
Expand Down Expand Up @@ -295,7 +296,11 @@ public static Task<bool> IsRunningOnComputeEngine()
return isRunningOnComputeEngineCached.Value;
}

private static async Task<bool> IsRunningOnComputeEngineNoCache()
private static async Task<bool> IsRunningOnComputeEngineNoCacheAsync() =>
await IsMetadataServerAvailableAsync().ConfigureAwait(false)
|| await IsGoogleBiosAsync().ConfigureAwait(false);

private static async Task<bool> IsMetadataServerAvailableAsync()
{
Logger.Info("Checking connectivity to ComputeEngine metadata server.");

Expand Down Expand Up @@ -337,8 +342,83 @@ private static async Task<bool> IsRunningOnComputeEngineNoCache()
}
}
// Only log after all attempts have failed.
Logger.Debug("Could not reach the Google Compute Engine metadata service. That is expected if this application is not running on GCE.");
Logger.Debug("Could not reach the Google Compute Engine metadata service. " +
"That is expected if this application is not running on GCE " +
"or on some cases where the metadata service is not available during application startup.");
return false;
}

private async static Task<bool> IsGoogleBiosAsync()
{
Logger.Info("Checking BIOS values to determine GCE residency.");
try
{
if (IsLinux())
{
return await IsLinuxGoogleBiosAsync().ConfigureAwait(false);
}
else if (IsWindows())
{
return IsWindowsGoogleBios();
}
else
{
Logger.Info("GCE residency detection through BIOS checking is only supported in Windows and Linux platforms.");
return false;
}
}
catch (Exception ex)
{
Logger.Debug($"Could not read BIOS: {ex}");
return false;
}

// Some of these will be simpler once we have acted on
// https://github.com/googleapis/google-api-dotnet-client/issues/2561.

bool IsWindows()
{
#if NET45 || NET461
// RuntimeInformation.IsOsPlatform is not available for these targets.
// But we know we are on Windows.
return true;
#else
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#endif
}

bool IsLinux()
{
#if NET45 || NET461
// RuntimeInformation.IsOsPlatform is not available for these targets.
// But we know we are on Windows.
return false;
#else
return RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
#endif
}

bool IsWindowsGoogleBios() => throw new NotImplementedException();

async Task<bool> IsLinuxGoogleBiosAsync()
{
Logger.Info("Checking BIOS values on Linux.");

string fileName = "/sys/class/dmi/id/product_name";
if (!File.Exists(fileName))
{
Logger.Debug($"Couldn't read file {fileName} containing BIOS mapped values.");
return false;
}

string productName;
using (var streamReader = new StreamReader(new FileStream("/sys/class/dmi/id/product_name", FileMode.Open, FileAccess.Read)))
{
productName = await streamReader.ReadLineAsync().ConfigureAwait(false);
}
productName = productName?.Trim();
return productName == "Google" || productName == "Google Compute Engine";
}
}
}
}

0 comments on commit c3ada0f

Please sign in to comment.