0

I have created my first Azure Functions application. From here I call a DynamoDB endpoint. The code I have written works on my local machine, but when deployed returns an exception with the message:

Request is missing Authentication Token

I have checked that appSettings.json are correct after the deployment has completed but I cant think of any other reasons why the Auth token would not be added, is this something azure specific or have I created really brittle code that will only work on under specific conditions?

appsetting.json

{
  "AWS": {
    "AccessKey": "my_access_key",
    "SecretKey": "my_secret_key",
    "AWSRegion": "eu-west-2"
  }
}

relevant code

public class Startup : FunctionsStartup
{
    private IConfigurationRoot _configuration;

    public Startup()
    {
        _configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();
    }

    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddHttpClient();

        builder.Services.AddScoped<IRoadmapService, RoadmapService>();
        builder.Services.AddRetroArcadeMachinesDataRead(_configuration);
        builder.Services.AddAutoMapper(typeof(Startup), typeof(MappingConfiguration));
    }
}

public static class StartupExtensions
{
    public static IServiceCollection AddRetroArcadeMachinesDataRead(this IServiceCollection services, IConfigurationRoot configuration)
    {
        var awsOptions = GetAWSOptions(configuration);

        services.AddDefaultAWSOptions(awsOptions);

        services.AddAWSService<IAmazonDynamoDB>();
        services.AddTransient<IDynamoDBContext, DynamoDBContext>();

        services.AddSingleton<IRoadmapRepository, DynamoDbRoadmapRepository>();

        return services;
    }

    private static AWSOptions GetAWSOptions(IConfigurationRoot configuration)
    {
        var awsOptions = configuration.GetAWSOptions();

        var accessKey = configuration.GetValue<string>("AWS:AccessKey");
        var secretKey = configuration.GetValue<string>("AWS:SecretKey");
        awsOptions.Credentials = new BasicAWSCredentials(accessKey, secretKey);
        awsOptions.Region = RegionEndpoint.EUWest2;

        return awsOptions;
    }

    private static AWSOptions GetAWSOptionsAlternateWayThatGivesTheSameResult(IConfigurationRoot configuration)
    {
        var netSDKFile = new NetSDKCredentialsFile();

        var profile = new CredentialProfile("basic_profile", new CredentialProfileOptions
        {
            AccessKey = configuration.GetValue<string>("AWS:AccessKey"),
            SecretKey = configuration.GetValue<string>("AWS:SecretKey")
        });
        profile.Region = RegionEndpoint.EUWest2;
        netSDKFile.RegisterProfile(profile);

        var awsOptions = configuration.GetAWSOptions();

        var isProfileExists = netSDKFile.TryGetProfile("basic_profile", out var credentialProfile);
        if (isProfileExists)
        {
            awsOptions.Credentials =
                new BasicAWSCredentials(credentialProfile.Options.AccessKey, credentialProfile.Options.SecretKey);
            awsOptions.Region = RegionEndpoint.EUWest2;
        }
        return awsOptions;
    }
}

public class DynamoDbRoadmapRepository : IRoadmapRepository
{
    private readonly IAmazonDynamoDB _dynamoDBClient;
    private readonly IDynamoDBContext _context;

    public DynamoDbRoadmapRepository(IAmazonDynamoDB dynamoDBClient, IDynamoDBContext context)
    {
        _dynamoDBClient = dynamoDBClient;
        _context = context;
    }

    public async Task<IEnumerable<RoadmapItemModel>> Get()
    {
        return await _context.ScanAsync<RoadmapItemModel>(new List<ScanCondition>()).GetRemainingAsync();
    }
}
Maurice
  • 11,482
  • 2
  • 25
  • 45
tony09uk
  • 2,841
  • 9
  • 45
  • 71

1 Answers1

0

I have finally resolved my issue. Thanks to the note on this answer. My problem was that I was trying to read from a appsettings.json file that I had added to the solution but not configured. I thought I had done so by adding

_configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();

but as mentioned in the previously linked answer this is no longer supported this. In addition to the below changes I had to add variables in azure as explained here

my code now read as follows:

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddHttpClient();

        builder.Services.AddScoped<IRoadmapService, RoadmapService>();
        
        var configuration = builder.GetContext().Configuration;
        builder.Services.AddRetroArcadeMachinesDataRead(configuration);
        builder.Services.AddAutoMapper(typeof(Startup), typeof(MappingConfiguration));
    }
}

public static class StartupExtensions
{
    public static IServiceCollection AddRetroArcadeMachinesDataRead(this IServiceCollection services, IConfiguration configuration)
    {
        var awsOptions = GetAWSOptions(configuration);

        services.AddDefaultAWSOptions(awsOptions);
        services.AddAWSService<IAmazonDynamoDB>();
        services.AddTransient<IDynamoDBContext, DynamoDBContext>();

        services.AddSingleton<IRoadmapRepository, DynamoDbRoadmapRepository>();

        return services;
    }

    private static AWSOptions GetAWSOptions(IConfiguration configuration)
    {
        var accessKey = Environment.GetEnvironmentVariable("AWS:AccessKey");
        var secretKey = Environment.GetEnvironmentVariable("AWS:SecretKey");

        var awsOptions = configuration.GetAWSOptions();

        awsOptions.Credentials = new BasicAWSCredentials(accessKey, secretKey);
        awsOptions.Region = RegionEndpoint.EUWest2;

        return awsOptions;
    }
}

If DI is required for the config values this explains how

tony09uk
  • 2,841
  • 9
  • 45
  • 71