Terraform provider for AWS: refreshing token for assume_role - terraform-provider-aws

How can configure terraform provider for AWS to make sure it will automatically re-new session if the current session will expire?
Here https://registry.terraform.io/providers/hashicorp/aws/latest/docs I cannot find any information about refreshing mechanism and AWS says https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html
“You must make sure that you get a new set of credentials before the old ones expire. In some SDKs, you can use a provider that manages the process of refreshing credentials for you; check the documentation for the SDK you're using.”
I found this thread https://github.com/hashicorp/terraform/issues/5927#issuecomment-436475932 and it is explained that somehow it is already implemented but where I can find more information about how refreshing mechanism works for terraform aws?

Use https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/rotating
resource "time_rotating" "example" {
rotation_minutes = 10
}
https://discuss.hashicorp.com/t/periodically-recreate-tls-private-key/27058

Related

SvelteKit: How to access Firebase authentication state from the server

I'm managing authentication state in a readable store which is grouped with a promise that resolves when the auth state is known (either signed in or out). The store is set internally via onAuthStateChange.
I'm trying to access this auth state from the server (+layout.server.ts and +page.server.ts) so that I can redirect the user to a sign-in page if they aren't authenticated, or load data from the database if (and only if) they are. No matter what I try, whenever I access this store from the server, its value is always null. I think this is because Firebase is only supposed to run on the client, although I'm not sure. Is there any way I can access this store from the server, or change my implementation so that Firebase runs in the server and passes auth state to the client? This blog post explains pretty much exactly what I want to do, but the solution here seems more complicated than it needs to be.
I've tried moving Firebase initialization code to the server (in both hooks.server.ts and +layout.server.ts), but there's no way for me to pass the auth object to the client because it can't be serialized (I get an error explaining this when I try to return it from a load function in +page.server.ts). I've also tried to handle authentication only using client-side code, but the server is responsible for loading data from the database, so in this case there's no way for me to verify a valid authentication state from the server.
author of the blog post you linked here.
You are correct in that the firebase client is only supposed to run on the client. If you want to access the Firebase services server-side you're supposed to use Firebase admin.
In my post I'm working around these limitations that firebase sets and unfortunately you do need that much code.
You are forced to do all the authentication in the frontend (firebase-client) and only afterwards you can inform the backend of the user info. (through the cookie)
Before I wrote this the ideal solution I had in my head was this:
Send the user to a login page that lists all the possible login providers.
The user chooses one and logs in.
the user gets redirected to a callback page where we can do something with the auth data in the backend.
I do think that something like this flow is possible if you're using custom tokens. But I'm sure that will be a whole load of even more complicated code.

AWS Cognito expired access token

In my application I have used aws cognito with next auth for user auth.
In the jwt callback that I have from api next-auth I receive an access token, which is then saved and sent to the client side. There, I save it in local storage and, among other things, I send it to my api which checks if it is correct.
The problem is that after an hour the access token expires and does not get a new one (always next-auth gives me old value). Has anyone had a similar flow and knows how to manage a session refresh? I will add that I am not automatically logged out because next-auth is managing it underneath, but it does not return the value of the new access token to me.
Do you have any ways how to manage this?
I can suggest a workaround that would take the least effort to solve this quickly. Amazon Cognito contains 3 kinds of tokens, the ID Token, Access Token and Refresh Token.
From the Amazon Cognito console, you can increase the validity of the token you're dealing with from there. A good idea is to refer to this answer.
Albeit you might need a couple of methods to assert security and robustness.

Is there a way to enable Firebase Auth via Email through an API/CLI?

We are transitioning to using Terraform to create our architecture on Google Compute, and part of it utilises Firebase for the front-end. So far, I have managed to get this all working fine, but have hit a snag on Firebase Auth. Essentially, I want to allow 'Email/Password' authentication on a Firbase project programmatically.
The above shows where you find the setting in the UI console, but I want to be able to do that via an API/CLI, and also set the 'Authorised Domain'.
Yes, as of November 2022, this is now possible, either using Terraform, or the gcloud CLI and a bit of scripting. Both methods make use of the REST Identity Toolkit API.
If using Terraform: Your config file needs to specify a google_identity_platform_project_default_config resource: the documentation for it is available here. By way of example – assuming you've already declared a google_project resource called my_project, you could add the google_identity_platform_project_default_config resource as follows:
resource "google_identity_platform_project_default_config" "myconfig" {
project = google_project.myproject.project_id
sign_in {
allow_duplicate_emails = false
anonymous {
enabled = false
}
email {
enabled = true
password_required = false
}
}
}
This would enable email+password authentication, disallow anonymous access, and disallow duplicate email addresses.
If using the gcloud CLI: This would be a good deal fiddlier. I haven't tested it out completely, but it is presumably equivalent to what Terraform is doing behind the scenes. You need to obtain a service account access token, then use cURL (or a similar tool/API) to amend the Identity Toolkit configuration using the PATCH method (documentation here), supplying the token in the "Authorization" header.
gcloud lets you get an access token using the command gcloud auth print-access-token, but according to this 2021 blog post1 by #DazWilkin, the token obtained using your regular human credentials can't perform the necessary PATCH operation; you need to use a token backed by a service account that has the correct permissions.
The blog post gives further details, but roughly, the steps are:
Create a service account and give it the correct permissions. (Not necessary if you already have an appropriate service account; such an account can be created either using the Firebase console or Terraform's google_service_account resource.)
Create a JSON service account key file. (Not necessary if you already have a key created, plus a JSON file for it. These JSON files contain an object with the keys "project_id", "private_key_id", and "private_key", and are exactly the same sort of file as gets generated from the Firebase console if you go to "Project Overview" / "Project Settings" / "Service Accounts" / "Generate new private key". They can also be created programmatically using Terraform's google_service_account_key resource.)
Allow gcloud to perform operations using the service account's permissions, by running gcloud's "auth activate-service-account" subcommand: something like
$ gcloud auth activate-service-account --key-file=/path/to/key-file.json EMAIL_ADDRESS_OF_SERVICE_ACCOUNT
Obtain an access token for the service account by running gcloud auth print-access-token EMAIL_ADDRESS_OF_SERVICE_ACCOUNT.
Supply that token in the header of an HTTP PATCH request using cURL.
For more details, see the blog post; it's concerned with amending the "authorized domains" list for a Firebase project, but enabling email/password authentication would be very similar.
1 Also mentioned in this stackoverflow answer.

Firebase custom auth provider I don't control/have access to?

Is it possible to use a custom authentication provider which I don't have any control over?
I develop an app in addition to a teachable course. Teachable is a platform like shopify where you can create online courses.
I want to use it as an auth provider, so a user, that already has an account can login with his teachable account.
To my knowledge custom authentications with auth tokes work like this: I send a request to my server with the entered user credentials. From my server I use these credential to login to teachable, if that was successful my server gets a callback and I return a token to my client, so the login was successful.
However as far as I know teachable doesn't have an api option for me to login and get a callback if it was successful.
What can I do about this? Also are there any security issues I didn't realized?
Your understanding of the flow to add a custom provider to Firebase Authentication is correct. You need to be able get the authenticated token from the provider, and mint a Firebase custom token from it.
If the provider you're looking to add doesn't have an API, you won't be able to add it as a custom provider to Firebase though.
I don't immediately see another way to connect the provider without an API.

Google OAuth Always Showing Consent Screen

I'm building an installed application that will have features requiring the Google Drive REST API using Qt and C++. I understand Qt is now releasing new libraries to support OAuth flows but let's assume I'm a student and learning to use OAuth at this layer is a requirement for this project.
In my application, I have a working OAuth flow for installed applications that ends with an Access Token and Refresh Token being stored using QSettings (I'm open to input on whether this is a disastrously bad idea too). The application requires no authentication/login for its own sake/data, but it does need authentication to Google for calling API's using an Access Token. This application has no associated web backend being hosted; its simple and should be deployable completely locally (I've written and included a simple TCP server that will receive the authorization redirect_uri and will run and close when called from within the application).
As such, I'm curious about the best way to make sure that, when a user opens my application and wants to use the Google Drive features, they are appropriately authenticated on Google's end. Say, if I maintain an access token in the registry, and this access token is granted per-user/per-application basis (right?), then how can I make sure only the user the token belongs to is able to make calls to the API with it?
Here's my understanding and approach; feel free to correct me or educate me if I've got the wrong interpretation.
If an Access Token is found, perform the following:
Open a browser page to a Google login domain and have the user authenticate there (this could prohibit a user from being able to use a cached login session that would have access to a token they otherwise shouldn't have access to)
If user has correctly authenticated with a Google account, return control to the application and make a test call to an API using the stored token.
If the call fails (responds with an invalid_credentials) I should be able to be sure its because the access token has expired and the application will go through the flow to renew an Access Token from a Refresh Token.
If no Access Token is initially found:
Start a normal OAuth installed application flow
Get the tokens and store them so that when the user opens the application next time the former procedure is used
My issue then is the first two steps if the Access Token is found. Nominally this could be done by the typical OAuth flow but it appears that when using a localhost as the redirect uri, Google will always prompt for consent, regardless of settings for prompt and access_type authorization query parameters.
What can be done to accomplish these first two steps in a way that my application can control (i.e. not a solution that relies on a backend server being hosted somewhere)?
If this question is too open-ended for SO requirements I can make some more restrictions/assumptions to limit the problem domain but I'd rather not do that yet in case I unknowingly rope off a good viable solution.
Thanks for reading! Sorry if its a verbose; I wanted to ensure my problem domain was fully fleshed out!
If you are using an installed application, I wouldn't recommend using or storing refresh tokens. Storing refresh tokens on the client side means that if an intruder gains access to the client's application, they have infinite access to the user's application without ever having to enter the user's credentials. If you do insist on having a refresh token, ensure you follow the Google's installed app flow, with the code_verifier parameter included in your requests.
If the access token is found, you should try to verify it, and if verified then use it at the google api, otherwise force the user to login again (or refresh it if you chose to still use refresh tokens).
If no access token is found, your flow sounds fine.
A few notes on loggin in with Google:
Google will only return a refresh token if you specify access_type=offline in your auth request.
Google will only return a refresh token on the user's first authorization request, unless you always specify prompt=consent in your query params.
In my experience, when leaving out the prompt query param, the user is not prompted for their consent again. If they are logged in to google, you will get a new access token, but no refresh token, unless you have prompt=consent.
I think the idea is you use prompt=consent if you have no record of the user ever using your application. Otherwise if they have used it before, you may prefer to use prompt=select_account to allow the user to select which account he wants to use in case he has more then one, or you can just use prompt=none.
This is just my understanding of it all.
My approach I ended up using was just to deploy with an SQLite db that will be stored in the AppData roaming directory. The db schema includes a field for the user's Name (from the OpenID IDToken field if it exists), the user's picture URL (again from IDToken if it exists), the refresh and access token strings (will be stored as encrypted strings when I get around to it), the user's UID/sub string, and a field for a user name and password.
These latter two fields are authentication fields for within my own application, which, again, I wanted to avoid but it seems impossible to do so. So the user will be prompted to enter a username and password into a form, and these credentials will be checked against the existing SQLite db file mentioned previously.
If they exist and are correct, the user gets logged in and will have access to their respective access and refresh token.
If the user has forgotten their password, they'll be asked for reconsent (going through the installed app flow again), and whatever password they provided during initial login will be used as the reset password. It is considered, for my purposes, that logging into Google for the installed app flow is proof enough that the user account belongs to them and they should have authorization to reset the password.
If the user is a new user and doesn't have a record in the local SQLite db file, then they can also click a button to "Create New Account" - which effectively goes through the authorization flow as well but this time a whole new record is posted to the SQLite db with the appropriate fields filled.
There's still more optimization that could be done but at least I am getting closer to the level of security and control of access to Google user accounts that I want.
I'm not marking this as an answer because I feel like this solution is still not desired and that there should be an easier way. So if someone has evidence or experience of providing an equivalent level of authentication control without needing to maintain a local user account database then I would be more than happy to mark such a method as the solution!
Thanks again!

Resources