Skip to content

Commit

Permalink
Remove private_key_data, private_key_type, public_key_data colu…
Browse files Browse the repository at this point in the history
…mns and add `public_key_data_pem` and `public_key_data_raw` columns to `gcp_service_account_key` table closes #448 (#449)
  • Loading branch information
ParthaI committed May 18, 2023
1 parent 26221a1 commit 6e6ebb2
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 21 deletions.
16 changes: 15 additions & 1 deletion docs/tables/gcp_service_account_key.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ where
key_type = 'USER_MANAGED';
```


### Validity time for the service account keys

```sql
Expand All @@ -29,3 +28,18 @@ select
from
gcp_service_account_key;
```

### Get public key data for a service account key

```sql
select
name,
key_type,
key_origin,
public_key_data_raw,
public_key_data_pem
from
gcp_service_account_key
where
service_account_name = 'test@myproject.iam.gserviceaccount.com';
```
88 changes: 69 additions & 19 deletions gcp/table_gcp_service_account_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
"google.golang.org/api/googleapi"
"google.golang.org/api/iam/v1"
)

Expand All @@ -28,53 +29,52 @@ func tableGcpServiceAccountKey(_ context.Context) *plugin.Table {
{
Name: "name",
Type: proto.ColumnType_STRING,
Description: "The friendly name that identifies the service account key",
Description: "The friendly name that identifies the service account key.",
Transform: transform.FromField("Name").Transform(lastPathElement),
},
{
Name: "service_account_name",
Type: proto.ColumnType_STRING,
Description: "Service account in which the key is located",
Description: "Service account in which the key is located.",
Transform: transform.FromP(getGcpServiceAccountKeyTurbotData, "ServiceAccountName"),
},
{
Name: "key_type",
Description: "The type of the service account key",
Description: "The type of the service account key.",
Type: proto.ColumnType_STRING,
},
{
Name: "key_algorithm",
Description: "Specifies the algorithm (and possibly key size) for the key",
Description: "Specifies the algorithm (and possibly key size) for the key.",
Type: proto.ColumnType_STRING,
},
{
Name: "key_origin",
Description: "Specifies the origin of the key",
Description: "Specifies the origin of the key.",
Type: proto.ColumnType_STRING,
},
{
Name: "private_key_data",
Description: "Specifies the private key data, which allows the assertion of the service account identity",
Name: "public_key_data_pem",
Description: "Specifies the public key data in PEM format.",
Type: proto.ColumnType_STRING,
Hydrate: getGcpServiceAccountKey,
Transform: transform.FromField("PublicKeyData").Transform(base64DecodedData),
},
{
Name: "private_key_type",
Description: "Specifies the output format for the private key",
Type: proto.ColumnType_STRING,
},
{
Name: "public_key_data",
Description: "Specifies the public key data",
Name: "public_key_data_raw",
Description: "Specifies the public key data in raw format.",
Type: proto.ColumnType_STRING,
Hydrate: getGcpServiceAccountKeyPublicKeyDataWithRawFormat,
Transform: transform.FromValue(),
},
{
Name: "valid_after_time",
Description: "Specifies the timestamp, after which the key can be used",
Description: "Specifies the timestamp, after which the key can be used.",
Type: proto.ColumnType_TIMESTAMP,
},
{
Name: "valid_before_time",
Description: "Specifies the timestamp, after which the key gets invalid",
Description: "Specifies the timestamp, after which the key gets invalid.",
Type: proto.ColumnType_TIMESTAMP,
},

Expand Down Expand Up @@ -138,6 +138,22 @@ func listGcpServiceAccountKeys(ctx context.Context, d *plugin.QueryData, h *plug
func getGcpServiceAccountKey(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
plugin.Logger(ctx).Trace("getGcpServiceAccountKey")

var name, serviceAccountName string
if h.Item != nil {
data := h.Item.(*iam.ServiceAccountKey)
name = strings.Split(data.Name, "/")[5]
splitName := strings.Split(data.Name, "/")
serviceAccountName = splitName[3]
} else {
name = d.EqualsQuals["name"].GetStringValue()
serviceAccountName = d.EqualsQuals["service_account_name"].GetStringValue()
}

// Empty check for the input param
if name == "" || serviceAccountName == "" {
return nil, nil
}

// Create Service Connection
service, err := IAMService(ctx, d)
if err != nil {
Expand All @@ -152,18 +168,52 @@ func getGcpServiceAccountKey(ctx context.Context, d *plugin.QueryData, h *plugin
}
project := projectId.(string)

name := d.EqualsQuals["name"].GetStringValue()
serviceAccountName := d.EqualsQuals["service_account_name"].GetStringValue()
keyName := "projects/" + project + "/serviceAccounts/" + serviceAccountName + "/keys/" + name

op, err := service.Projects.ServiceAccounts.Keys.Get(keyName).Do()
queryParameter := googleapi.QueryParameter("publicKeyType", "TYPE_X509_PEM_FILE")

op, err := service.Projects.ServiceAccounts.Keys.Get(keyName).Do(queryParameter)
if err != nil {
return nil, err
}

return op, nil
}

func getGcpServiceAccountKeyPublicKeyDataWithRawFormat(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {

var name, serviceAccountName string
data := h.Item.(*iam.ServiceAccountKey)
name = strings.Split(data.Name, "/")[5]
splitName := strings.Split(data.Name, "/")
serviceAccountName = splitName[3]

// Create Service Connection
service, err := IAMService(ctx, d)
if err != nil {
return nil, err
}

// Get project details
getProjectCached := plugin.HydrateFunc(getProject).WithCache()
projectId, err := getProjectCached(ctx, d, h)
if err != nil {
return nil, err
}
project := projectId.(string)

keyName := "projects/" + project + "/serviceAccounts/" + serviceAccountName + "/keys/" + name

queryParameter := googleapi.QueryParameter("publicKeyType", "TYPE_RAW_PUBLIC_KEY")

op, err := service.Projects.ServiceAccounts.Keys.Get(keyName).Do(queryParameter)
if err != nil {
return nil, err
}

return op.PublicKeyData, nil
}

/// TRANSFORM FUNCTIONS

func getGcpServiceAccountKeyTurbotData(ctx context.Context, d *transform.TransformData) (interface{}, error) {
Expand Down
14 changes: 13 additions & 1 deletion gcp/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package gcp
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"unicode/utf8"

"github.com/mitchellh/go-homedir"
"github.com/turbot/go-kit/types"
Expand Down Expand Up @@ -163,6 +165,17 @@ func getProjectFromConfig(connection *plugin.Connection) string {
return ""
}

func base64DecodedData(_ context.Context, d *transform.TransformData) (interface{}, error) {
data, err := base64.StdEncoding.DecodeString(types.SafeString(d.Value))
// check if CorruptInputError or invalid UTF-8
if err != nil {
return nil, nil
} else if !utf8.Valid(data) {
return types.SafeString(d.Value), nil
}
return data, nil
}

// Set project values from config and return client options
func setSessionConfig(ctx context.Context, connection *plugin.Connection) []option.ClientOption {
gcpConfig := GetConfig(connection)
Expand Down Expand Up @@ -290,7 +303,6 @@ func buildQueryFilter(filterQuals []filterQualMap, equalQuals plugin.KeyColumnEq
* status in ('TERMINATED', 'RUNNING') and
* cpu_platform = 'Intel Haswell' and
* not deletion_protection
* -----------------------STEAMPIPE QUAL INFO-----------------------------------------
* Column: deletion_protection, Operator: '<>', Value: 'true'
* Column: status, Operator: '=', Value: '[TERMINATED RUNNING]'
Expand Down

0 comments on commit 6e6ebb2

Please sign in to comment.