Skip to content

Commit

Permalink
Fix auth session token not being cached properly. Fixes #441 (#442)
Browse files Browse the repository at this point in the history
This commit also fixes some incorrect plugin name references in the index doc
  • Loading branch information
LalitLab authored Jan 19, 2022
1 parent ca94cdd commit 505431e
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 21 deletions.
54 changes: 35 additions & 19 deletions azure/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/azure/auth"
"github.com/Azure/go-autorest/autorest/azure/cli"
"github.com/turbot/go-kit/types"
"github.com/turbot/steampipe-plugin-sdk/plugin"
)

Expand All @@ -40,6 +41,7 @@ type Session struct {
*/
func GetNewSession(ctx context.Context, d *plugin.QueryData, tokenAudience string) (session *Session, err error) {
logger := plugin.Logger(ctx)

cacheKey := "GetNewSession"
if cachedData, ok := d.ConnectionManager.Cache.Get(cacheKey); ok {
session = cachedData.(*Session)
Expand All @@ -50,6 +52,8 @@ func GetNewSession(ctx context.Context, d *plugin.QueryData, tokenAudience strin
}
}

logger.Debug("Auth session not found in cache, creating new session")

var subscriptionID, tenantID string
settings := auth.EnvironmentSettings{
Values: map[string]string{},
Expand Down Expand Up @@ -113,7 +117,7 @@ func GetNewSession(ctx context.Context, d *plugin.QueryData, tokenAudience strin
if azureConfig.Environment != nil {
env, err := azure.EnvironmentFromName(*azureConfig.Environment)
if err != nil {
logger.Debug("GetNewSession_", "Error getting environment from name with config environment", err)
logger.Error("GetNewSession", "Error getting environment from name with config environment", err)
return nil, err
}
settings.Environment = env
Expand All @@ -124,7 +128,7 @@ func GetNewSession(ctx context.Context, d *plugin.QueryData, tokenAudience strin
if ok {
env, err = azure.EnvironmentFromName(envName)
if err != nil {
logger.Debug("GetNewSession_", "Error getting environment from name with no config environment", err)
logger.Error("GetNewSession", "Error getting environment from name with no config environment", err)
return nil, err
}
settings.Values[auth.EnvironmentName] = envName
Expand All @@ -134,28 +138,30 @@ func GetNewSession(ctx context.Context, d *plugin.QueryData, tokenAudience strin

authMethod, resource, err := getApplicableAuthorizationDetails(ctx, settings, tokenAudience)
if err != nil {
logger.Debug("GetNewSession__", "getApplicableAuthorizationDetails error", err)
logger.Error("GetNewSession", "getApplicableAuthorizationDetails error", err)
return nil, err
}
settings.Values[auth.Resource] = resource

var authorizer autorest.Authorizer
var expiresOn time.Time
var expiresOn *time.Time

// so if it was not in cache - create session
switch authMethod {
case "Environment":
logger.Trace("Creating new session authorizer from environment")
authorizer, err = settings.GetAuthorizer()
if err != nil {
logger.Debug("GetNewSession__", "NewAuthorizerFromEnvironmentWithResource error", err)
logger.Error("GetNewSession", "NewAuthorizerFromEnvironmentWithResource error", err)
return nil, err
}

// Get the subscription ID and tenant ID for "GRAPH" token audience
case "CLI":
logger.Trace("Creating new session authorizer from Azure CLI")
authorizer, err = auth.NewAuthorizerFromCLIWithResource(resource)
if err != nil {
logger.Debug("GetNewSession__", "NewAuthorizerFromCLIWithResource error", err)
logger.Error("GetNewSession", "NewAuthorizerFromCLIWithResource error", err)

// Check if the password was changed and the session token is stored in
// the system, or if the CLI is outdated
Expand All @@ -165,16 +171,17 @@ func GetNewSession(ctx context.Context, d *plugin.QueryData, tokenAudience strin
return nil, err
}
default:
logger.Trace("Getting token for authorizer from Azure CLI")
token, err := cli.GetTokenFromCLI(resource)
if err != nil {
return nil, err
}

adalToken, err := token.ToADALToken()
expiresOn = adalToken.Expires()
expiresOn = types.Time(adalToken.Expires())

if err != nil {
logger.Debug("GetNewSession__", "NewAuthorizerFromCLIWithResource error", err)
logger.Error("GetNewSession", "Get token from Azure CLI error", err)

// Check if the password was changed and the session token is stored in
// the system, or if the CLI is outdated
Expand All @@ -186,38 +193,47 @@ func GetNewSession(ctx context.Context, d *plugin.QueryData, tokenAudience strin
authorizer = autorest.NewBearerAuthorizer(&adalToken)
}

if authMethod == "CLI" {
// Get the subscription ID and tenant ID from CLI if not set in connection
// config or environment variables
if authMethod == "CLI" && (settings.Values[auth.SubscriptionID] == "" || settings.Values[auth.TenantID] == "") {
logger.Trace("Getting subscription ID and/or tenant ID from from Azure CLI")
subscription, err := getSubscriptionFromCLI(resource)
if err != nil {
logger.Debug("GetNewSession__", "getSubscriptionFromCLI error", err)
logger.Error("GetNewSession", "getSubscriptionFromCLI error", err)
return nil, err
}
tenantID = subscription.TenantID

// If "AZURE_SUBSCRIPTION_ID" is set then it will take precedence over the subscription set in the CLI
// Subscription ID set in config file or environment variable takes
// precedence over the subscription ID set in the CLI
if subscriptionID == "" {
subscriptionID = subscription.SubscriptionID
logger.Trace("Setting subscription ID from Azure CLI", "subscription_id", subscriptionID)
}
}

sess := &Session{
Authorizer: authorizer,
CloudEnvironment: settings.Environment.Name,
Expires: &expiresOn,
Expires: expiresOn,
GraphEndpoint: settings.Environment.GraphEndpoint,
ResourceManagerEndpoint: settings.Environment.ResourceManagerEndpoint,
StorageEndpointSuffix: settings.Environment.StorageEndpointSuffix,
SubscriptionID: subscriptionID,
TenantID: tenantID,
}

if sess.Expires != nil {
d.ConnectionManager.Cache.SetWithTTL(cacheKey, sess, time.Until(*sess.Expires))
var expireMins time.Duration
if expiresOn != nil {
expireMins = time.Until(*sess.Expires)
} else {
// Cache for 55 minutes to avoid expiry issue
d.ConnectionManager.Cache.SetWithTTL(cacheKey, sess, time.Minute*55)
expireMins = time.Minute * 55
}

logger.Debug("Session saved in cache", "expiration_time", expireMins)
d.ConnectionManager.Cache.SetWithTTL(cacheKey, sess, expireMins)

return sess, err
}

Expand All @@ -238,7 +254,7 @@ func getApplicableAuthorizationDetails(ctx context.Context, settings auth.Enviro
authMethod = "Environment"
}

logger.Trace("getApplicableAuthorizationDetails_", "Auth Method: ", authMethod)
logger.Debug("getApplicableAuthorizationDetails", "auth_method", authMethod)

var environment azure.Environment
// Get the environment endpoint to be used for authorization
Expand All @@ -247,13 +263,13 @@ func getApplicableAuthorizationDetails(ctx context.Context, settings auth.Enviro
} else {
environment, err = azure.EnvironmentFromName(environmentName)
if err != nil {
logger.Error("Unable to get azure environment", "ERROR", err)
logger.Error("getApplicableAuthorizationDetails", "get_environment_name_error", err)
return
}
settings.Environment = environment
}

logger.Trace("getApplicableAuthorizationDetails_", "tokenAudience: ", tokenAudience)
logger.Debug("getApplicableAuthorizationDetails", "token_audience", tokenAudience)

switch tokenAudience {
case "GRAPH":
Expand All @@ -266,7 +282,7 @@ func getApplicableAuthorizationDetails(ctx context.Context, settings auth.Enviro
resource = settings.Environment.ResourceManagerEndpoint
}

logger.Trace("getApplicableAuthorizationDetails_", "resource: ", resource)
logger.Debug("getApplicableAuthorizationDetails", "resource", resource)

return
}
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ steampipe plugin install azure
| Credentials | Use the `az login` command to setup your [Azure Default Connection](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli). |
| Permissions | Grant the `Global Reader` permission to your user. |
| Radius | Each connection represents a single Azure Subscription. |
| Resolution | 1. Credentials explicitly set in a steampipe config file (`~/.steampipe/config/azuread.spc`).<br />2. Credentials specified in [environment variables](#credentials-from-environment-variables), e.g., `AZURE_SUBSCRIPTION_ID`. |
| Resolution | 1. Credentials explicitly set in a steampipe config file (`~/.steampipe/config/azure.spc`).<br />2. Credentials specified in [environment variables](#credentials-from-environment-variables), e.g., `AZURE_SUBSCRIPTION_ID`. |

### Configuration

Expand Down Expand Up @@ -197,7 +197,7 @@ Steampipe works with managed identities (formerly known as Managed Service Ident

```hcl
connection "azure_msi" {
plugin = "azuread"
plugin = "azure"
tenant_id = "00000000-0000-0000-0000-000000000000"
client_id = "00000000-0000-0000-0000-000000000000"
subscription_id = "00000000-0000-0000-0000-000000000000"
Expand Down

0 comments on commit 505431e

Please sign in to comment.