Providing credentials without the keys being displayed in the code

Hello,
I hope I am phrasing my question correctly. I have a set of keys I need to assign to a variable during compilation. This is how I am doing it at the moment:

static const char* AWS_ACCESS_KEY = "AKIAEXAMPLE123";
static const char* AWS_SECRET_KEY = "example!§&%/$)"12312432242";

But I dont want to have those keys being displayed in my code. The keys are also stored in a file using AWS Toolkit in VScode. In my python program I do not have to provide the keys at all since the boto3 library simply gets the somehow from the AWS Credential Manager.

In every example in the internet the code is alway simply inserted in the code but I do not think this is best practice.
Is there a way to access the content from the files and assign it correctly during compilation?
Or what do you see as best practice?

Hi @lkyslevin ! You can set your secrets as environment variables and then pass them to your code as macros, for example on Windows in CMD:

set AWS_ACCESS_KEY="\"WHATEVER\""
set AWS_SECRET_KEY="\"WHATEVER\""

Then configure a pair of build flags in your platformio.ini:

[env:nucleo_f401re]
platform = ststm32
board = nucleo_f401re
build_flags =
    -D ENV_AWS_ACCESS_KEY="${sysenv.AWS_ACCESS_KEY}"
    -D ENV_AWS_SECRET_KEY="${sysenv.AWS_SECRET_KEY}"

Now you should have access to those variables in your code:

static const char* AWS_ACCESS_KEY = ENV_AWS_ACCESS_KEY;
static const char* AWS_SECRET_KEY = ENV_AWS_SECRET_KEY;

Thank you for this approach. The only other thing which came to my mind is storing the keys and certificates on SPIFFS, though everybody could read it out if he wanted to.

However, I am facing an error implementing your approach I do not understand.

This is my .ini:

[env:firebeetle32]

platform = espressif32
board = firebeetle32
framework = arduino
board_build.partitions = default_16MB.csv
lib_ldf_mode = chain+
build_flags =
     -I include
     -D ENV_AWS_ACCESS_KEY="${sysenv.AWS_ACCESS_KEY}"
     -D ENV_AWS_SECRET_KEY="${sysenv.AWS_SECRET_KEY}"
lib_deps =
     bblanchon/ArduinoJson@^6.17.3
     paulstoffregen/Time@^1.6.1
     adafruit/Adafruit ADS1X15@^2.2.0
     adafruit/Adafruit BusIO@^1.9.3
     knolleary/PubSubClient@^2.8

In my secrets.h:

// AWS credentials
static const char* AWS_ACCESS_KEY = ENV_AWS_ACCESS_KEY;
static const char* AWS_SECRET_KEY = ENV_AWS_SECRET_KEY;

I checked my system (not user) environment variables on windows and the keys are there. The error I get is:

include/secrets.h:15:55: error: expected primary-expression before ';' token
 static const char* AWS_ACCESS_KEY = ENV_AWS_ACCESS_KEY;
                                                       ^
include/secrets.h:16:55: error: expected primary-expression before ';' token
 static const char* AWS_SECRET_KEY = ENV_AWS_SECRET_KEY;

Any idea what I could be doing wrong?

Maybe you have some special characters in your secrets that are not properly escaped? For example & is a special symbol and it should be escaped with ^& on Windows.

I only have a + and a / nothing else special in my secret key.

I also tried using getenv() and tried to print it:

static const char* AWS_ACCESS_KEY = getenv("AWS_ACCESS_KEY");
static const char* AWS_SECRET_KEY = getenv("AWS_SECRET_KEY");

String secret_access_key = AWS_ACCESS_KEY;
printf("ACCESS KEY: %s\r\n", secret_access_key);

But it does print an empty string.

Not sure what is goging on.

I also tried using getenv() and tried to print it:

You cannot use it as the getenv function is executed in runtime.

Any idea what I could be doing wrong?

Are you sure the env variable is properly wrapped with extra \" as I mentioned in my code above? I’d recommend you to add the -save-temps flag to the build_flags option. This flag will force the compiler to generate a preprocessed file with expanded macros so you will see what exactly is passed to your source file. A new file with the .ii extension should appear somewhere in the root of your project.

You cannot use it as the getenv function is executed in runtime.
Damn, chatGPT tricked me once more. However, I noticed this later by myself and though calling getenv() during runtime, the string was empty. However, using CLI I was able to retrieve the variables.

Well, though I should have done this way earlier (but it always takes so long with this old machine) I simply rebooted my computer. After that the variables could be accessed. I added the wrap \" at another location:

    -D ENV_AWS_ACCESS_KEY="\"${sysenv.AWS_ACCESS_KEY}\""
    -D ENV_AWS_SECRET_KEY="\"${sysenv.AWS_SECRET_KEY}\""

And finally I could use them and I did not need to escape any sign like + or /.

Afterwards I was playing around a little bit with the system environmental variables and I checked when they got updated in my code but couldnt find a reproducible pattern so in the end restarting VScode, the cmd line tool or the machine is mandatory.

One final note: I needed to open a cmd line tool as administrator and use

setx AWS_SECRET_KEY "\"WHATEVER\"" /m

this sets the variable in the system and not the local environment of the machine. Some more info can be found here