Skip to content

Commit

Permalink
Update for better credential_process support
Browse files Browse the repository at this point in the history
Update aws-okta to support `okta_aws_role_arn` so profiles can be
configured easier when using the credential process feature of the AWS
SDK.

In the AWS config `role_arn` requires either `source_profile` or
`credential_source` to be specified for the profile, otherwise it is
detected as partial credentials, ignoring the `credential_process`
field. Allow `aws-okta` to use the specifed role in the field
`okta_aws_role_arn` reduces the number of chained profiles required to
correctly use bare awscli, kubectl and other AWS SDK enabled
applications.
  • Loading branch information
neuralsandwich committed Feb 17, 2021
1 parent 6470595 commit abfb53d
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 80 deletions.
205 changes: 139 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

### Windows

See [docs/windows.md](docs/windows.md) for information on getting this working with Windows.
See [docs/windows.md](docs/windows.md) for information on getting this working
with Windows.

## Usage

Expand All @@ -18,83 +19,111 @@ See [docs/windows.md](docs/windows.md) for information on getting this working w
$ aws-okta add
```

This will prompt you for your Okta organization, custom domain, region, username, and password. These credentials will then be stored in your keyring for future use.
This will prompt you for your Okta organization, custom domain, region,
username, and password. These credentials will then be stored in your keyring
for future use.

### Exec

```bash
$ aws-okta exec <profile> -- <command>
```

Exec will assume the role specified by the given aws config profile and execute a command with the proper environment variables set. This command is a drop-in replacement for `aws-vault exec` and accepts all of the same command line flags:
### Configuring your AWS config

```bash
$ aws-okta help exec
exec will run the command specified with aws credentials set in the environment

Usage:
aws-okta exec <profile> -- <command>
The most seamless way to use `aws-okta` is via AWS SDK config credential
process. To do so you will need to setup your AWS config as `aws-okta` assumes
that your base role is one that has been configured for Okta's SAML integration
by your Okta admin.

Flags:
-a, --assume-role-ttl duration Expiration time for assumed role (default 1h0m0s)
-h, --help help for exec
-t, --session-ttl duration Expiration time for okta role session (default 1h0m0s)
Okta provides a guide for setting up that integration
[here](https://help.okta.com/en/prod/Content/Topics/DeploymentGuides/AWS/aws-deployment.htm).
During that configuration, your admin should be able to grab the AWS App Embed
URL from the General tab of the AWS application in your Okta org. You will need
to set that value in your `~/.aws/config` file, for example:

Global Flags:
-b, --backend string Secret backend to use [kwallet secret-service file] (default "file")
-d, --debug Enable debug logging
```ini
[okta]
aws_saml_url = home/amazon_aws/0ac4qfegf372HSvKF6a3/965
```

### Exec for EKS and Kubernetes

`aws-okta` can also be used to authenticate `kubectl` to your AWS EKS cluster. Assuming you have [installed `kubectl`](https://docs.aws.amazon.com/eks/latest/userguide/install-kubectl.html), [setup your kubeconfig](https://docs.aws.amazon.com/eks/latest/userguide/create-kubeconfig.html) and [installed `aws-iam-authenticator`](https://docs.aws.amazon.com/eks/latest/userguide/configure-kubectl.html), you can now access your EKS cluster with `kubectl`. Note that on a new cluster, your Okta CLI user needs to be using the same assumed role as the one who created the cluster. Otherwise, your cluster needs to have been configured to allow your assumed role.
Next, you need to set up your base Okta role. This will be one your admin
created while setting up the integration. It should be specified similar to
to any other aws profile. However, instead of `role_arn` we will use
`okta_aws_role_arn`:

```bash
$ aws-okta exec <profile> -- kubectl version --short
```
[profile okta-dev]
# okta_aws_role_arn is used here instead of role_arn because
# role_arn requires either source_profile or credential_source to be set
okta_aws_role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
credential_process = aws-okta cred-process okta-dev
```

Your setup may require additional roles to be configured if your admin has set
up a more complicated role scheme like cross account roles. For more details on
the authentication process, see the internals section.

Likewise, most Kubernetes projects should work, like Helm and Ark.
### cred-process

```bash
$ aws-okta exec <profile> -- helm version --short
aws-okta cred-process profile
```

### Configuring your aws config
`cred-process` generates the required JSON output for the AWS CLI external
process sourcing. This is set in the `credential_process` field in the AWS
config file.

`aws-okta` assumes that your base role is one that has been configured for Okta's SAML integration by your Okta admin. Okta provides a guide for setting up that integration [here](https://support.okta.com/help/servlet/fileField?retURL=%2Fhelp%2Farticles%2FKnowledge_Article%2FAmazon-Web-Services-and-Okta-Integration-Guide&entityId=ka0F0000000MeyyIAC&field=File_Attachment__Body__s). During that configuration, your admin should be able to grab the AWS App Embed URL from the General tab of the AWS application in your Okta org. You will need to set that value in your `~/.aws/config` file, for example:
If your organization requires MFA it's advices to use [Okta
Verify](https://help.okta.com/en/prod/end-user/Content/Topics/end-user/ov-new-install.htm)
as the AWS CLI may hide output required to completing the MFA process. A fuller
example of the `credential_process` command would be:

```ini
[okta]
aws_saml_url = home/amazon_aws/0ac4qfegf372HSvKF6a3/965
[profile okta-dev]
okta_aws_role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
credential_process = aws-okta cred-process --mfa-factor-type push --mfa-provider okta okta-dev
```

```
Usage:
aws-okta cred-process <profile> [flags]
Next, you need to set up your base Okta role. This will be one your admin created while setting up the integration. It should be specified like any other aws profile:
Examples:
[profile foo]
credential_process = aws-okta cred-process profile
```ini
[profile okta-dev]
role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
region = <region>
Flags:
-a, --assume-role-ttl duration Expiration time for assumed role (default 1h0m0s)
-h, --help help for cred-process
-p, --pretty Pretty print display
-t, --session-ttl duration Expiration time for okta role session (default 1h0m0s)
Global Flags:
-b, --backend string Secret backend to use [keychain pass file]
-d, --debug Enable debug logging
--mfa-duo-device string Device to use phone1, phone2, u2f or token (default "phone1")
--mfa-factor-type string MFA Factor Type to use (eg push, token:software:totp)
--mfa-provider string MFA Provider to use (eg DUO, OKTA, GOOGLE)
--session-cache-single-item (alpha) Enable single-item session cache; aka AWS_OKTA_SESSION_CACHE_SINGLE_ITEM
```

Your setup may require additional roles to be configured if your admin has set up a more complicated role scheme like cross account roles. For more details on the authentication process, see the internals section.

#### A more complex example

The `aws_saml_url` can be set in the "okta" ini section, or on a per profile basis. This is useful if, for example, your organization has several Okta Apps (i.e. one for dev/qa and one for prod, or one for internal use and one for integrations with third party providers). For example:
The `aws_saml_url` can be set in the "okta" ini section, or on a per profile
basis. This is useful if, for example, your organization has several Okta Apps
(i.e. one for dev/qa and one for prod, or one for internal use and one for
integrations with third party providers). For example:

```ini
[okta]
# This is the "default" Okta App
aws_saml_url = home/amazon_aws/cuZGoka9dAIFcyG0UllG/214

[profile dev]
# This profile uses the default Okta app
role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
[profile okta-dev]
okta_aws_role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
credential_process = aws-okta cred-process okta-dev

[profile integrations-auth]
# This is a distinct Okta App
aws_saml_url = home/amazon_aws/woezQTbGWUaLSrYDvINU/214
role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
okta_aws_role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
credential_process = aws-okta cred-process integrations-auth

[profile vendor]
# This profile uses the "integrations-auth" Okta app combined with secondary role assumption
Expand Down Expand Up @@ -124,12 +153,12 @@ define keyring key for each profile:
[profile account-a]
# This is a distinct Okta App
aws_saml_url = home/amazon_aws/woezQTbGWUaLSrYDvINU/214
role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
okta_aws_rolerole_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
okta_account_name = account-a

[profile account-b]
aws_saml_url = home/amazon_aws/woezQTbGaDAA4rYDvINU/123
role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
okta_aws_role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
okta_account_name = account-b
```

Expand All @@ -153,65 +182,109 @@ The AWS assume role TTL can also be set per-profile in the aws config:
# Example with an initial and secondary role that are configured with a max session duration of 12 hours
[profile ttldemo]
aws_saml_url = home/amazon_aws/cuZGoka9dAIFcyG0UllG/214
role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
okta_aws_role_arn = arn:aws:iam::<account-id>:role/<okta-role-name>
session_ttl = 12h

[profile ttldemo-role]
source_profile = ttldemo
role_arn = arn:aws:iam::<account-id>:role/<secondary-role-name>
okta_aws_role_arn = arn:aws:iam::<account-id>:role/<secondary-role-name>
assume_role_ttl = 12h
```

#### Multi-factor Authentication (MFA) configuration

If you have a single MFA factor configured, that factor will be automatically selected. By default, if you have multiple available MFA factors, then you will be prompted to select which one to use. However, if you have multiple factors and want to specify which factor to use, you can do one of the following:
If you have a single MFA factor configured, that factor will be automatically
selected. By default, if you have multiple available MFA factors, then you will
be prompted to select which one to use. However, if you have multiple factors
and want to specify which factor to use, you can do one of the following:

* Specify on the command line with `--mfa-provider` and `--mfa-factor-type`
* Specify with environment variables `AWS_OKTA_MFA_PROVIDER` and `AWS_OKTA_MFA_FACTOR_TYPE`
* Specify in your aws config with `mfa_provider` and `mfa_factor_type`

### Exec

When using applications that do not integrate the AWS SDK and need credentials
to be in the environment you can used `aws-okta exec`

```bash
$ aws-okta exec <profile> -- <command>
```

Exec will assume the role specified by the given aws config profile and execute
a command with the proper environment variables set. This command is a drop-in
replacement for `aws-vault exec` and accepts all of the same command line flags:

```bash
$ aws-okta help exec
exec will run the command specified with aws credentials set in the environment

Usage:
aws-okta exec <profile> -- <command>

Flags:
-a, --assume-role-ttl duration Expiration time for assumed role (default 1h0m0s)
-h, --help help for exec
-t, --session-ttl duration Expiration time for okta role session (default 1h0m0s)

Global Flags:
-b, --backend string Secret backend to use [kwallet secret-service file] (default "file")
-d, --debug Enable debug logging
```

### Exec for EKS and Kubernetes

`aws-okta` can also be used to authenticate `kubectl` to your AWS EKS cluster.
Assuming you have [installed
`kubectl`](https://docs.aws.amazon.com/eks/latest/userguide/install-kubectl.html),
[setup your
kubeconfig](https://docs.aws.amazon.com/eks/latest/userguide/create-kubeconfig.html).
you can now access your EKS cluster with `kubectl`. Note that on a new cluster,
your Okta CLI user needs to be using the same assumed role as the one who
created the cluster. Otherwise, your cluster needs to have been configured to
allow your assumed role.

```bash
$ kubectl version --short
```

### Shell completion

`aws-okta` provides shell completion support for BASH and ZSH via the `aws-okta completion` command.
`aws-okta` provides shell completion support for BASH and ZSH via the `aws-okta
completion` command.

## Backends

We use 99design's keyring package that they use in `aws-vault`. Because of this, you can choose between different pluggable secret storage backends just like in `aws-vault`. You can either set your backend from the command line as a flag, or set the `AWS_OKTA_BACKEND` environment variable.
We use 99design's keyring package that they use in `aws-vault`. Because of
this, you can choose between different pluggable secret storage backends just
like in `aws-vault`. You can either set your backend from the command line as a
flag, or set the `AWS_OKTA_BACKEND` environment variable.

For Linux / Ubuntu add the following to your bash config / zshrc etc:

```
export AWS_OKTA_BACKEND=secret-service
```

## --session-cache-single-item aka AWS_OKTA_SESSION_CACHE_SINGLE_ITEM (alpha)

This flag enables a new secure session cache that stores all sessions in the same keyring item. For macOS users, this means drastically fewer authorization prompts when upgrading or running local builds.
This flag enables a new secure session cache that stores all sessions in the
same keyring item. For macOS users, this means drastically fewer authorization
prompts when upgrading or running local builds.

No provision is made to migrate sessions between session caches.

Implemented in [https://github.com/segmentio/aws-okta/issues/146](#146).

## Local Development

If you're developing in Linux, you'll need to get `libusb`. For Ubuntu, install the libusb-1.0-0-dev or use the `Dockerfile` provided in the repo.
If you're developing in Linux, you'll need to get `libusb`. For Ubuntu, install
the libusb-1.0-0-dev or use the `Dockerfile` provided in the repo.

## Running Tests

`make test`

## Releasing

Pushing a new tag will cause Circle to automatically create and push a linux release. After this is done, you should run (from a mac):

```bash
$ export CIRCLE_TAG=`git describe --tags`
$ make release-mac
```

## Analytics

`aws-okta` includes some usage analytics code which Segment uses internally for tracking usage of internal tools. This analytics code is turned off by default, and can only be enabled via a linker flag at build time, which we do not set for public github releases.

## Internals

### Authentication process
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/99designs/keyring v1.1.6 h1:kVDC2uCgVwecxCk+9zoCt2uEL6dt+dfVzMvGgnVcIuM=
github.com/99designs/keyring v1.1.6/go.mod h1:16e0ds7LGQQcT59QqkTg72Hh5ShM51Byv5PEmW6uoRU=
Expand Down
30 changes: 16 additions & 14 deletions lib/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ func (p *Provider) getOktaAccountName() string {

func (p *Provider) getSamlSessionCreds() (sts.Credentials, error) {
var profileARN string
var ok bool
source := sourceProfile(p.profile, p.profiles)
oktaAwsSAMLUrl, err := p.getSamlURL()
if err != nil {
Expand All @@ -226,23 +225,26 @@ func (p *Provider) getSamlSessionCreds() (sts.Credentials, error) {
oktaSessionCookieKey := p.getOktaSessionCookieKey()
oktaAccountName := p.getOktaAccountName()

if _, ok := p.profiles[source]["okta_aws_role_arn"]; ok {
profileARN, _ = p.profiles[source]["okta_aws_role_arn"]
} else if _, ok := p.profiles[source]["role_arn"]; ok {
profileARN, _ = p.profiles[source]["role_arn"]
} else {
// profile does not have an okta_aws_role_arn or role_arn. This is ok
// as the user will be promted to choose a role from all available roles
// Support profiles similar to below
// [profile my-profile]
// output = json
// aws_saml_url = /home/some_saml_url
// mfa_provider = FIDO
// mfa_factor_type = u2f
log.Debugf("Profile '%s' does not have role_arn", source)
}

// if the assumable role is passed it have it override what is in the profile
if p.AssumeRoleArn != "" {
profileARN = p.AssumeRoleArn
log.Debug("Overriding Assumable role with: ", profileARN)
} else {
profileARN, ok = p.profiles[source]["role_arn"]
if !ok {
// profile does not have a role_arn. This is ok as the user will be promted
// to choose a role from all available roles
// Support profiles similar to below
// [profile my-profile]
// output = json
// aws_saml_url = /home/some_saml_url
// mfa_provider = FIDO
// mfa_factor_type = u2f
log.Debugf("Profile '%s' does not have role_arn", source)
}
}

provider := OktaProvider{
Expand Down

0 comments on commit abfb53d

Please sign in to comment.