I have an app that makes authenticated REST API calls to another product. As such, it requires a bit of configuration, most of which is supplied through an AdminPage and stored via the StorageAPI. However, in following Atlassian’s recommendations for security, the app relies on being able to access the client secret value as an encrypted environment variable.
This has worked flawlessly through the development and testing stages, but on the first attempt to install the app in a customer instance (shared via Installation Link from the Developer Console) we found that they aren’t able to set environment variables for their instance / environments using the Forge CLI.
Did we miss something? Surely there is some way for them to set their own environment variables, right? Or is there some way I can set them programmatically from the app itself - that way I could collect that value via the AdminPage as well but have it stored as an env var rather than in StorageAPI?
For reference, even attempting to list environment variables, they would get errors like this:
Error: Server error: [{“message”:“Permission denied”,“locations”:[{“line”:2,“column”:3}],“path”:[“installationsByAppEnvironment”],“extensions”:{“errorSource”:“UNDERLYING_SERVICE”,“statusCode”:400,“errorType”:“UNAUTHORIZED_TO_MANAGE_APP_ENVIRONMENTS”,“errorDetails”:{“code”:“UNAUTHORIZED_TO_MANAGE_APP_ENVIRONMENTS”,“message”:“Permission denied”},“classification”:“DataFetchingException”}}], requestId=6a0e9c09f613342e
Perhaps a different line of questioning will trigger a response.
So along those lines, is anyone else doing something similar - storing/using a piece of sensitive information that would need to differ for each deployment of your app. If so, how are you going about it?
FWIW, I ended up having to go against recommended approach and leverage the Storage API to store my OAuth secret. I did take some steps to mitigate risk though:
The value is encrypted before being stored
The value is only decrypted at the point it is actually injected into the API call
This decryption and (external) API call happens server-side (in a webtrigger) rather than on the client
Because of the above - and the seeming lack of any other way to get around the current limitation - I felt pretty comfortable proceeding with the use of the Storage API. I’m sure there are some things I’m not considering, but from the outside looking in, I think a similar ‘encrypted’ flag to what exists for environment variables would be a perfect addition to the Storage API. The API wouldn’t even have to expose the unencrypted value directly as it could provide a util call to handle that, further mitigating the risk of exposing sensitive data. At the end of the day though, I think it comes down to the individual developers making the right choices around security and having a platform that simply provides the tools to do it.
the environment variables are set per app/environment and not per installation/site
the environment variables are set by the app developer and not by the customers
This means that, before distributing the app to a customer, the variables will need to be set via the Forge CLI by your team. The app will then be able to access those for all the sites where it is installed.
--environment production is the flag to set a variable in the production environment. If not specified, the variable will be set for the development environment which is the default. I’ll add this flag to the commands below considering the previous posts here.
forge variables set --environment production MY_KEY my-value for a non encrypted variable
forge variables set --encrypt --environment production MY_KEY my-value for an encrypted variable
for the CLI to prompt for the options, enter forge variables set --environment production, this can help when entering RSA private keys (based on this other topic)
use forge variables list --environment production to check the variables currently set in a specific environment
Thank you for the response, Caterina! You’ve explained the current behavior and intended usage of environment variables very well. This was pretty much what I came to suspect and understand even though it was was not at all my initial impression of how they worked.
Speaking only for myself, I’m happy with the solution I was able to put in place by leveraging the Storage API and encrypting the values I put there, but ultimately I hope the platform itself will expose some convenience tools to accomplish this since the easier it is to implement something in a secure manner, the more the platform and ecosystem of apps developed for it will naturally trend toward security.
My small team manages dozens of apps/integrations, so once we had a workable solution to this issue we moved on and I never dug into this any more. I’ll certainly take a look at the docs on this and put something on our backlog to leverage it in the next release.
For convenience for anyone following: @ibuchanan is referring to the get/set/deleteSecret methods added to the Storage API.
theres noting in the docs explaning how to deploy variables to production and that variables are set per app and not per site/installation
e.g this
just to show how variables are set in production
because i couldnt find a place where is said that so i had been stuck the last 12 days until you replied