-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature work/aws account id parsing (#2920)
- Loading branch information
1 parent
c36d25c
commit 55cc8a4
Showing
15 changed files
with
281 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/AwsSdk/AwsAccountIdDecoder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Copyright 2020 New Relic, Inc. All rights reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
using System; | ||
|
||
namespace NewRelic.Agent.Extensions.AwsSdk | ||
{ | ||
public static class AwsAccountIdDecoder | ||
{ | ||
// magic number | ||
private const long Mask = 0x7FFFFFFFFF80; | ||
|
||
public static string GetAccountId(string awsAccessKeyId) | ||
{ | ||
if (string.IsNullOrEmpty(awsAccessKeyId)) | ||
{ | ||
throw new ArgumentNullException(nameof(awsAccessKeyId), "AWS Access Key ID cannot be null or empty."); | ||
} | ||
|
||
if (awsAccessKeyId.Length < 14) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(awsAccessKeyId), "AWS Access Key ID must be at least 14 characters long."); | ||
} | ||
|
||
string accessKeyWithoutPrefix = awsAccessKeyId.Substring(4).ToLowerInvariant(); | ||
long encodedAccount = Base32Decode(accessKeyWithoutPrefix); | ||
|
||
return ((encodedAccount & Mask) >> 7).ToString(); | ||
} | ||
|
||
/// <summary> | ||
/// Performs a Base-32 decode of the specified input string. | ||
/// Allowed character range is a-z and 2-7. 'a' being 0 and '7' is 31. | ||
/// | ||
/// public to allow for unit testing | ||
/// </summary> | ||
/// <param name="src">The string to be decoded. Must be at least 10 characters.</param> | ||
/// <returns>A long containing first 6 bytes of the base 32 decoded data.</returns> | ||
/// <exception cref="ArgumentException">If src has less than 10 characters.</exception> | ||
/// <exception cref="ArgumentOutOfRangeException">If src contains invalid characters for Base-32</exception> | ||
public static long Base32Decode(string src) | ||
{ | ||
if (string.IsNullOrEmpty(src)) | ||
{ | ||
throw new ArgumentNullException(nameof(src), "The input string cannot be null or empty."); | ||
} | ||
|
||
if (src.Length < 10) | ||
{ | ||
throw new ArgumentException("The input string must be at least 10 characters long.", nameof(src)); | ||
} | ||
|
||
long baseValue = 0; | ||
for (int i = 0; i < 10; i++) | ||
{ | ||
baseValue <<= 5; | ||
char c = src[i]; | ||
baseValue += c switch | ||
{ | ||
>= 'a' and <= 'z' => c - 'a', | ||
>= '2' and <= '7' => c - '2' + 26, | ||
_ => throw new ArgumentOutOfRangeException(nameof(src), | ||
"The input string must contain only characters in the range a-z and 2-7.") | ||
}; | ||
} | ||
|
||
return baseValue >> 2; | ||
} | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/AmazonServiceClientWrapper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Copyright 2020 New Relic, Inc. All rights reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
using System; | ||
using NewRelic.Agent.Api; | ||
using NewRelic.Agent.Extensions.AwsSdk; | ||
using NewRelic.Agent.Extensions.Providers.Wrapper; | ||
|
||
namespace NewRelic.Providers.Wrapper.AwsSdk | ||
{ | ||
public class AmazonServiceClientWrapper : IWrapper | ||
{ | ||
/// <summary> | ||
/// The AWS account id. | ||
/// Parsed from the access key in the credentials of the client - or fall back to the configuration value if parsing fails. | ||
/// Assumes only a single account id is used in the application. | ||
/// </summary> | ||
public static string AwsAccountId { get; private set; } | ||
|
||
public bool IsTransactionRequired => false; | ||
|
||
public CanWrapResponse CanWrap(InstrumentedMethodInfo instrumentedMethodInfo) | ||
{ | ||
return new CanWrapResponse(instrumentedMethodInfo.RequestedWrapperName == nameof(AmazonServiceClientWrapper)); | ||
} | ||
|
||
public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction) | ||
{ | ||
if (AwsAccountId != null) | ||
return Delegates.NoOp; | ||
|
||
try | ||
{ | ||
// get the AWSCredentials parameter | ||
dynamic awsCredentials = instrumentedMethodCall.MethodCall.MethodArguments[0]; | ||
|
||
dynamic immutableCredentials = awsCredentials.GetCredentials(); | ||
string accessKey = immutableCredentials.AccessKey; | ||
|
||
// convert the access key to an account id | ||
AwsAccountId = AwsAccountIdDecoder.GetAccountId(accessKey); | ||
} | ||
catch (Exception e) | ||
{ | ||
agent.Logger.Info($"Unable to parse AWS Account ID from AccessKey. Using AccountId from configuration instead. Exception: {e.Message}"); | ||
AwsAccountId = agent.Configuration.AwsAccountId; | ||
} | ||
|
||
return Delegates.NoOp; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.