If you are thinking of using an external CI/CD tool like Github to deploy to Amazon Web Services (AWS), you are probably wondering how to securely connect your pipelines to your AWS account. For a long time, one common way was to set up an IAM user and then store the access keys for that user in GitHub secrets for use with GitHub Actions. These access keys required a lot of manual work, such as setting up different users for different projects, rotating keys after a certain period, etc. But, those days are gone!
Let’s learn how we can use OpenID Connect (OIDC) to securely deploy to AWS from Github Actions, and how we can use GitHub to secure deployments to specific AWS environments. By utilizing OIDC, we can configure AWS to trust GitHub as a federated identity provider, and then use ID tokens in Github Actions workflows to authenticate to AWS and access resources. We can create separate IAM roles for different purposes and allow workflows to assume those roles in a granular way. OIDC allows GitHub Actions workflows to access resources in AWS, without needing to store the AWS credentials as long-lived GitHub secrets.
In this multi-part series we will try to demystify the secrets of OIDC and explain how they work and what’s the trust model between AWS and an OIDC provider like GitHub. We will also explain all the steps required to integrate AWS with GitHub.
But before we dive into more detail on how to set this up, let’s first get a good understanding of what OIDC is and how it works.
Delegated authorization
The first thing we need to cover is: OAuth.
OAuth 2.0 is a security protocol where you give an application permission to access your data in another application instead of giving them your username and password. You essentially give an application a key that gives specific permission to access your data or do things on your behalf in another application. The steps to grant permission, or consent, are often referred to as delegated authorization. You authorize an application to access your data or use features in another application on your behalf without giving them your password. And, you can take back that key whenever you want!
The OAuth (authorization code) flow
The OAuth flow in this example is made of visible steps ( — ) to grant consent, as well as some invisible steps ( - - - ) where the two services agree on a secure way of exchanging information. This is known as the front and back channel, which we will cover in a next article.
OAuth terminology
Before moving on, let’s explain some of the OAuth terminology first.
Resource owner That’s you. You are the owner of your identity, your data and any actions that can be performed with your accounts.
Client The client is the application that wants to access data or perform actions on behalf of you, the resource owner.
Authorization server The authorization server is the application that knows the resource owner where the resource owner already has an account.
Resource server The resource server is the API or service the client wants to use on behalf of the resource owner. Sometimes the authorization server and the resource server are the same server, however, there are cases where they will not be the same server.
Redirect URI This is the URL the authorization server will redirect the resource owner back to after granting permission to the client. This is sometimes referred to as the callback URL.
Response type The type of information the client expects to receive the most common response type is code, where the client expects to receive an authorization code.
Client ID and Client secret This ID is used to identify the client with the authorization server. There’s also a client secret. This is a secret password that only the client and the authorization server know. This allows them to securely share information privately behind the scenes.
Authorization code This is a short-lived temporary code the authorization server sends back to the client. The client then privately sends the authorization code back to the authorization server along with the client secret in exchange for an access token.
Access token This is the key the client will use from that point forward to communicate with the resource server. This is like a key or a key card that gives the client permission to request data or perform actions with the resource server on your behalf.
And specifically…
Scope These are the granular permissions the client wants such as access to specific data or to perform specific actions.
Consent The authorization server takes the scope the client is requesting and verifies with the resource owner whether or not they want to give the client permission.
Now that we have demystified some of the OAuth 2.0 terminology, let’s have a closer look on how this OAuth authorization flow works:
- The client clicks on a login link in the web application.
- The client is redirected to an OAuth authorization server.
- The authorization server verifies who you are and if necessary prompts for a login.
- The client provides credentials according to the enabled login options.
- The client is shown a list of permissions (based on the scopes) that will be granted to the web application by logging in and granting consent.
- The client is redirected to the application using the redirect URI (callback URL), along with a temporary authorization code.
- Then the client contacts the authorization server directly; it does not use the resource owner’s browser (a.k.a. back channel) and securely sends its client ID, client secret and the authorization code. The authorization server verifies the data and responds with an access token.
- The client can then use the access token to gain access to the target API with the user’s credentials. The access token is a value the client doesn’t understand. However, the client can use the access token to send requests to the resource server.
- The resource server verifies the access token and if valid responds with the resources requested.
As the name implies, the client secret must be kept secret so that only the client and authorization server know what it is. This is how the authorization server can verify the client.
Introducing: The ID token
Now, let’s talk about OIDC.
OAuth 2.0 is only designed for authorization: For granting access to data and features (permissions) from one application to another. OAuth is like giving an application, the client, a key. That key is useful but it doesn’t tell the client who you are or anything about you.
Open ID Connect, or OIDC, is a thin layer that sits on top of OAuth 2.0 and adds functionality around login and profile information about the person who is logged in instead of only providing a key. OIDC is like giving the client application a badge. The badge not only gives the client specific permissions; it also provides some basic information about who you are.
Where OAuth enables authorization from an app to another, OIDC enables a client to establish a login session often referred to as authentication, as well as to gain information about the person logged in, the resource owner, which is often called identity.
When an authorization server supports OIDC, it is sometimes called an identity provider since it provides information about the resource owner back to the client.
The OpenID Connect flow looks the same as OAuth. The only differences are, in the initial request, a specific scope of openid is used, and in the final exchange the client receives both an access token and an ID token.
As mentioned earlier, the access token is a value the client doesn’t understand, however, the ID token is very different. The ID token is a specifically formatted string of characters known as a JSON Web Token or JWT. A JWT is unreadable for you and me, but the client can extract information embedded in the JWT such as your ID name when you logged in and the ID token expiration. The data inside the ID token are called claims. We will explain this in more detail in a next article.
Conclusion
So, in summary, the use cases for these two protocols would be:
In this article, we explained some of the key concepts and differences of OAuth and OIDC. We have learned that OAuth and OIDC are almost identical, but what differentiates OIDC from OAuth is that it adds some extra functionality regarding login and profile information.
In Part 2 of this series, we will build on these steps and show how to integrate AWS with GitHub as a federated identity provider.