Skip to content

Commit

Permalink
Merge pull request #96 from Cox-Automotive/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
amagana3 committed Oct 20, 2020
2 parents 967d3d5 + a6c4390 commit 74141d5
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ glide.lock
# VSCode
.vscode
.DS_Store
.terraform/
.terraform/
gpg/
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ release:
GOOS=windows GOARCH=amd64 go build -ldflags "-X main.versionNumber=$(TRAVIS_TAG)" -o release/terraform-provider-alks_v$(TRAVIS_TAG).exe -mod=vendor $(package)
zip release/terraform-provider-alks-windows-amd64.zip release/terraform-provider-alks_v$(TRAVIS_TAG).exe

shasum -a 256 release/*.tar.gz release/*.zip > release/terraform-provider-alks_v$(TRAVIS_TAG)_SHA256SUMS

echo "$GPG_KEY" | base64 --decode --ignore-garbage | gpg --batch --allow-secret-key-import --import

@gpg --batch -c --passphrase $(GPG_PASSPHRASE) -u C182B91A3A62B0D5 --detach-sign release/terraform-provider-alks_v$(TRAVIS_TAG)_SHA256SUMS

rm release/terraform-provider-alks_v$(TRAVIS_TAG).exe
rm release/terraform-provider-alks_v$(TRAVIS_TAG)

19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,25 @@ resource "alks_ltk" "test_ltk_user" {
| `access_key` | Computed | n/a | string | Generated access key for the LTK user. Note: This is saved in the state file, so please be aware of this. |
| `secret_key` | Computed | n/a | string | Generated secret key for the LTK user. Note: This is saved in the state file, so please be aware of this. |

### Data Source Configuration
#### `alks_keys`
```tf
data "alks_keys" "account_keys" {
providers: alks.my_alias
}
```

| Value | Type | Forces New | Value Type | Description |
| -------------- | -------- | ---------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `access_key` | Computed | n/a | string | Generated access key for the specified provider. If multiple providers, it takes the `provider` field. Otherwise uses the initial provider. |
| `secret_key` | Computed | n/a | string | Generated secret key for the specified provider. If multiple providers, it takes the `provider` field. Otherwise uses the initial provider. |
| `session_token`| Computed | n/a | string | Generated session token for the specified provider. If multiple providers, it takes the `provider` field. Otherwise uses the initial provider. |
| `account` | Computed | n/a | string | The account number of the returned keys.
| `role` | Computed | n/a | string | The role from the returned keys.

_Note: This does not take any arguments. See below._
- **How it works**: Whatever your default provider credentials are, will be used. If multiple providers have been configured, then one can point the data source to return keys for specific providers using `providers` field with a specific `alias`.


## Example

Expand Down
58 changes: 48 additions & 10 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
// Version number, to be injected at link time
// to set, add `-ldflags "-X main.versionNumber=1.2.3"` to the go build command
var versionNumber string
var ErrNoValidCredentialSources = errors.New(`No valid credential sources found for ALKS Provider.
var errNoValidCredentialSources = errors.New(`No valid credential sources found for ALKS Provider.
Please see https://github.com/Cox-Automotive/terraform-provider-alks#authentication for more information on
providing credentials for the ALKS Provider`)

Expand All @@ -32,6 +32,8 @@ type Config struct {
CredsFilename string
Profile string
AssumeRole assumeRoleDetails
Account string
Role string
}

type assumeRoleDetails struct {
Expand Down Expand Up @@ -76,14 +78,14 @@ func getCredentialsFromSession(c *Config) (*credentials.Credentials, error) {
sess, err = session.NewSessionWithOptions(*options)
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" {
return nil, ErrNoValidCredentialSources
return nil, errNoValidCredentialSources
}
return nil, fmt.Errorf("Error creating AWS session: %s", err)
}
creds := sess.Config.Credentials
cp, err := sess.Config.Credentials.Get()
if err != nil {
return nil, ErrNoValidCredentialSources
return nil, errNoValidCredentialSources
}

log.Printf("[DEBUG] Got session credentials from provider: %s\n", cp.ProviderName)
Expand All @@ -93,7 +95,7 @@ func getCredentialsFromSession(c *Config) (*credentials.Credentials, error) {

// Client returns a properly configured ALKS client or an appropriate error if initialization fails
func (c *Config) Client() (*alks.Client, error) {
log.Println("[DEBUG] Validting STS credentials")
log.Println("[DEBUG] Validating STS credentials")

// lookup credentials
creds := getCredentials(c)
Expand All @@ -115,7 +117,7 @@ func (c *Config) Client() (*alks.Client, error) {
}
}
if cpErr != nil {
return nil, ErrNoValidCredentialSources
return nil, errNoValidCredentialSources
}

// create a new session to test credentails
Expand Down Expand Up @@ -161,25 +163,32 @@ func (c *Config) Client() (*alks.Client, error) {

// make a basic api call to test creds are valid
cident, serr := stsconn.GetCallerIdentity(&sts.GetCallerIdentityInput{})

// check for valid creds
if serr != nil {
return nil, serr
}

// got good creds, create alks sts client
client, err := alks.NewSTSClient(c.URL, cp.AccessKeyID, cp.SecretAccessKey, cp.SessionToken)
if err != nil {
return nil, err
}

// 1. Check if calling for a specific account
if len(c.Account) > 0 && len(c.Role) > 0 {
// 2. Generate client specified
client, err = generateNewClient(c, client)
if err != nil {
return nil, err
}
}

// check if the user is using a assume-role IAM admin session or MI.
if isValidIAM(cident.Arn, client) != true {
return nil, errors.New("Looks like you are not using ALKS IAM credentials. This will result in errors when creating roles. \n " +
"Note: If using ALKS CLI to get credentials, be sure to use the '-i' flag. \n Please see https://coxautoinc.sharepoint.com/sites/service-internal-tools-team/SitePages/ALKS-Terraform-Provider---Troubleshooting.aspx for more information.")
}

if err != nil {
return nil, err
}

client.SetUserAgent(fmt.Sprintf("alks-terraform-provider-%s", getPluginVersion()))

log.Println("[INFO] ALKS Client configured")
Expand Down Expand Up @@ -215,9 +224,38 @@ func isValidIAM(arn *string, client *alks.Client) bool {
if err != nil {
return false
}

return true
}

func splitBy(r rune) bool {
return r == ':' || r == '/'
}

func generateNewClient(c *Config, client *alks.Client) (*alks.Client, error) {

// 3. Create account string
newAccDetail := c.Account + "/ALKS" + c.Role

// Calling for the same account; exit early
if strings.Contains(newAccDetail, client.AccountDetails.Account) {
return client, nil
}

// 4. Alright, new credentials needed - swap em out.
client.AccountDetails.Account = newAccDetail
client.AccountDetails.Role = c.Role

newCreds, err := client.CreateIamSession()
if err != nil {
return nil, err
}

newClient, err := alks.NewSTSClient(c.URL, newCreds.AccessKey, newCreds.SecretKey, newCreds.SessionToken)
if err != nil {
return nil, err
}

// 5. Return this new client for provider
return newClient, nil
}
58 changes: 58 additions & 0 deletions data_source_alks_keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package main

import (
"github.com/Cox-Automotive/alks-go"
"github.com/hashicorp/terraform/helper/schema"
"log"
"strings"
)

func dataSourceAlksKeys() *schema.Resource {
return &schema.Resource{
Read: dataSourceAlksKeysRead,
Schema: map[string]*schema.Schema{
"access_key": {
Type: schema.TypeString,
Computed: true,
},
"secret_key": {
Type: schema.TypeString,
Computed: true,
},
"session_token": {
Type: schema.TypeString,
Computed: true,
},
"account": {
Type: schema.TypeString,
Computed: true,
},
"role": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceAlksKeysRead(d *schema.ResourceData, meta interface{}) error {
log.Printf("[INFO] ALKS Keys Data Source Read")

client := meta.(*alks.Client)
resp, err := client.CreateIamSession()

if err != nil {
return err
}

// Return the information to user.
_ = d.Set("access_key", resp.AccessKey)
_ = d.Set("secret_key", resp.SecretKey)
_ = d.Set("session_token", resp.SessionToken)
_ = d.Set("account", client.AccountDetails.Account)
_ = d.Set("role", strings.Split(client.AccountDetails.Role, "/")[0])

d.SetId(client.AccountDetails.Account)

return nil
}
45 changes: 39 additions & 6 deletions examples/alks.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,51 @@
# PROVIDERS
#
provider "alks" {
url = "https://alks.foo.com/rest"
url = "https://alks.foo.com/rest"
}

# Second ALKS provider, for an account I have access to.
provider "alks" {
url = "https://alks.foo.com/rest"
account = "<account No>"
role = "<role>"
alias = "nonprod"
}

data "alks_keys" "non_prod_keys" {
provider = alks.nonprod
}

provider "aws" {
region = "us-east-1"
region = "us-east-1"
}

# CREATE IAM ROLE
# Second AWS provider, using credentials retreived from data source.
provider "aws" {
region = "us-east-1"
alias = "nonprod"

# data source alks keys
access_key = data.alks_keys.non_prod_keys.access_key
secret_key = data.alks_keys.non_prod_keys.secret_key
token = data.alks_keys.non_prod_keys.session_token
}

# CREATE IAM ROLE -- Initial Provider
resource "alks_iamrole" "test_role" {
name = "aba-test-123456"
type = "Amazon EC2"
include_default_policies = false
name = "TEST-DELETE"
type = "AWS CodeBuild"
include_default_policies = false
enable_alks_access = true
}

# CREATE IAM ROLE -- Secondary Provider
resource "alks_iamrole" "test_role_nonprod" {
provider = alks.nonprod
name = "TEST-DELETE"
type = "AWS CodeBuild"
include_default_policies = false
enable_alks_access = true
}

# ATTACH POLICY
Expand Down
12 changes: 12 additions & 0 deletions examples/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
terraform {
required_providers {
alks = {
source = "coxautoinc.com/engineering-enablement/alks"
version = "1.4.4"
}
aws = {
source = "hashicorp/aws"
}
}
required_version = ">= 0.13"
}
18 changes: 18 additions & 0 deletions provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ func Provider() terraform.ResourceProvider {
Description: "The path to the shared credentials file. If not set this defaults to ~/.aws/credentials.",
DefaultFunc: schema.EnvDefaultFunc("AWS_SHARED_CREDENTIALS_FILE", nil),
},
"account": {
Type: schema.TypeString,
Optional: true,
Description: "The account which you'd like to retrieve credentials for.",
DefaultFunc: schema.EnvDefaultFunc("Account", nil),
},
"role": {
Type: schema.TypeString,
Optional: true,
Description: "The role which you'd like to retrieve credentials for.",
DefaultFunc: schema.EnvDefaultFunc("Role", nil),
},
"assume_role": assumeRoleSchema(),
},

Expand All @@ -68,6 +80,10 @@ func Provider() terraform.ResourceProvider {
"alks_ltk": resourceAlksLtk(),
},

DataSourcesMap: map[string]*schema.Resource{
"alks_keys": dataSourceAlksKeys(),
},

ConfigureFunc: providerConfigure,
}
}
Expand Down Expand Up @@ -111,6 +127,8 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
SecretKey: d.Get("secret_key").(string),
Token: d.Get("token").(string),
Profile: d.Get("profile").(string),
Account: d.Get("account").(string),
Role: d.Get("role").(string),
}

assumeRoleList := d.Get("assume_role").(*schema.Set).List()
Expand Down

0 comments on commit 74141d5

Please sign in to comment.