Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 139 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,145 @@
## My Project
# ACK Stats

TODO: Fill this README out!
A tool for extracting and analyzing AWS API operations from service models, designed to support the AWS Controllers for Kubernetes (ACK) project.

Be sure to:
## Features

* Change the title in this README
* Edit your repository description on GitHub
- Parses AWS service API models to extract all available operations
- Checks ACK controller codebases to identify which operations are implemented
- Uses AWS Bedrock to classify operations as control plane vs data plane (optional)
- Generates IAM policies for supported operations (optional)
- Process multiple AWS services in a single run
- Outputs detailed metadata in JSON format for further analysis

## Prerequisites

- Go 1.22 or later
- AWS credentials configured (required for Bedrock classification)
- Access to AWS service model files (expects `../api-models-aws/models/` directory)
- Access to ACK controller directories (expects `../<service>-controller/` directories)

## Usage

### Multiple Services

Process multiple services at once:

```bash
go run main.go --service=dynamodb,lambda,s3 --output=./results
```

### With Classification

Enable Bedrock-powered operation classification:

```bash
go run main.go --service=dynamodb --output=./results --classify
```

### With IAM Policy Generation

Generate recommended IAM policies for supported operations:

```bash
go run main.go --service=dynamodb --output=./results --generate-policies
```

### Combined Features

Use classification and policy generation together:

```bash
go run main.go --service=dynamodb --output=./results --classify --generate-policies
```

### Command Line Options

- `--service`: AWS service name(s), comma-separated (required)
- `--output`: Output directory for JSON files (required)
- `--classify`: Enable AWS Bedrock classification of operations (optional)
- `--generate-policies`: Generate recommended IAM policies for supported operations (optional)

## Output Format

### Operations JSON

The tool generates operations JSON files (`<service>-operations.json`) with the following structure:

```json
{
"service_name": "dynamodb",
"total_operations": 42,
"supported_operations": 28,
"control_plane_operations": 15,
"supported_control_plane_operations": 12,
"operations": [
{
"name": "CreateTable",
"type": "control_plane",
"file": "pkg/resource/table/hooks.go",
"line": 145
},
{
"name": "GetItem",
"type": "data_plane",
"file": "",
"line": 0
}
]
}
```

#### Field Descriptions

- `service_name`: AWS service identifier
- `total_operations`: Total number of operations found in API model
- `supported_operations`: Number of operations implemented in ACK controller
- `control_plane_operations`: Number of control plane operations (when classification enabled)
- `supported_control_plane_operations`: Number of implemented control plane operations
- `operations`: Array of operation details with implementation status

### IAM Policy JSON

When `--generate-policies` is enabled, the tool also generates IAM policy JSON files (`<service>-policy.json`) with the following structure:

```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:CreateTable",
"dynamodb:DeleteTable",
"dynamodb:DescribeTable",
"dynamodb:UpdateTable"
],
"Resource": "arn:aws:dynamodb:*:*:*"
}
]
}
```

#### IAM Policy Features

- Contains only permissions for **supported operations** (those implemented in the controller)
- Generates standard AWS IAM policy JSON format for direct use

## Operation Classification

The tool uses a two-tier classification approach:

### Classification
- **Supported Operations**: Operations found in existing controller code are automatically marked as **Control Plane**
- This assumes that implemented operations are inherently control plane by nature

### AWS Bedrock Classification
When `--classify` is enabled, only **unsupported operations** are sent to AWS Bedrock's Claude model for classification:

- **Control Plane**: Operations that manage AWS infrastructure (create, configure, delete resources)
- **Data Plane**: Operations that work with data within existing resources

This classification helps identify which operations are most critical for Kubernetes resource management.

## Security

Expand Down
27 changes: 27 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module github.com/aws-controllers-k8s/stats

go 1.22

toolchain go1.24.2

require (
github.com/aws/aws-sdk-go-v2 v1.37.1
github.com/aws/aws-sdk-go-v2/config v1.30.2
github.com/aws/aws-sdk-go-v2/service/bedrockagentruntime v1.46.1
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.18.2 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.26.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.31.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.35.1 // indirect
github.com/aws/smithy-go v1.22.5 // indirect
)
34 changes: 34 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
github.com/aws/aws-sdk-go-v2 v1.37.1 h1:SMUxeNz3Z6nqGsXv0JuJXc8w5YMtrQMuIBmDx//bBDY=
github.com/aws/aws-sdk-go-v2 v1.37.1/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0 h1:6GMWV6CNpA/6fbFHnoAjrv4+LGfyTqZz2LtCHnspgDg=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0/go.mod h1:/mXlTIVG9jbxkqDnr5UQNQxW1HRYxeGklkM9vAFeabg=
github.com/aws/aws-sdk-go-v2/config v1.30.2 h1:YE1BmSc4fFYqFgN1mN8uzrtc7R9x+7oSWeX8ckoltAw=
github.com/aws/aws-sdk-go-v2/config v1.30.2/go.mod h1:UNrLGZ6jfAVjgVJpkIxjLufRJqTXCVYOpkeVf83kwBo=
github.com/aws/aws-sdk-go-v2/credentials v1.18.2 h1:mfm0GKY/PHLhs7KO0sUaOtFnIQ15Qqxt+wXbO/5fIfs=
github.com/aws/aws-sdk-go-v2/credentials v1.18.2/go.mod h1:v0SdJX6ayPeZFQxgXUKw5RhLpAoZUuynxWDfh8+Eknc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.1 h1:owmNBboeA0kHKDcdF8KiSXmrIuXZustfMGGytv6OMkM=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.1/go.mod h1:Bg1miN59SGxrZqlP8vJZSmXW+1N8Y1MjQDq1OfuNod8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.1 h1:ksZXBYv80EFTcgc8OJO48aQ8XDWXIQL7gGasPeCoTzI=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.1/go.mod h1:HSksQyyJETVZS7uM54cir0IgxttTD+8aEoJMPGepHBI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.1 h1:+dn/xF/05utS7tUhjIcndbuaPjfll2LhbH1cCDGLYUQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.1/go.mod h1:hyAGz30LHdm5KBZDI58MXx5lDVZ5CUfvfTZvMu4HCZo=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
github.com/aws/aws-sdk-go-v2/service/bedrockagentruntime v1.46.1 h1:Pn4YQ3iS092EYpCvNvgJEa6sBBdxkam2PmRgtaYMoyc=
github.com/aws/aws-sdk-go-v2/service/bedrockagentruntime v1.46.1/go.mod h1:9B4NxtljjRiW25asvRpQC5FI8CSbb7qr65KpvmgeQe8=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.1 h1:ky79ysLMxhwk5rxJtS+ILd3Mc8kC5fhsLBrP27r6h4I=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.1/go.mod h1:+2MmkvFvPYM1vsozBWduoLJUi5maxFk5B7KJFECujhY=
github.com/aws/aws-sdk-go-v2/service/sso v1.26.1 h1:uWaz3DoNK9MNhm7i6UGxqufwu3BEuJZm72WlpGwyVtY=
github.com/aws/aws-sdk-go-v2/service/sso v1.26.1/go.mod h1:ILpVNjL0BO+Z3Mm0SbEeUoYS9e0eJWV1BxNppp0fcb8=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.31.1 h1:XdG6/o1/ZDmn3wJU5SRAejHaWgKS4zHv0jBamuKuS2k=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.31.1/go.mod h1:oiotGTKadCOCl3vg/tYh4k45JlDF81Ka8rdumNhEnIQ=
github.com/aws/aws-sdk-go-v2/service/sts v1.35.1 h1:iF4Xxkc0H9c/K2dS0zZw3SCkj0Z7n6AMnUiiyoJND+I=
github.com/aws/aws-sdk-go-v2/service/sts v1.35.1/go.mod h1:0bxIatfN0aLq4mjoLDeBpOjOke68OsFlXPDFJ7V0MYw=
github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw=
github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
112 changes: 112 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.


package main

import (
"flag"
"fmt"
"os"
"strings"

extractor "github.com/aws-controllers-k8s/stats/pkg"
)

func main() {
servicesFlag := flag.String("service", "", "AWS service name(s), comma-separated (e.g., acm,dynamodb,lambda)")
outputFlag := flag.String("output", "", "Output directory for files (creates <service>-operations.json)")
classifyFlag := flag.Bool("classify", false, "Enable AWS Bedrock inline agent classification of operations as control plane vs data plane")
generatePoliciesFlag := flag.Bool("generate-policies", false, "Generate recommended IAM policies for supported operations")
flag.Parse()

if *servicesFlag == "" || *outputFlag == "" {
fmt.Println("Usage: go run main.go --service=<service1>[,service2,service3...] --output=<directory> [--classify] [--generate-policies]")
fmt.Println("Examples:")
fmt.Println(" go run main.go --service=dynamodb --output=./results --classify --generate-policies")
os.Exit(1)
}


// Parse comma-separated services
services := strings.Split(*servicesFlag, ",")
for i, service := range services {
services[i] = strings.TrimSpace(service)
}
var features []string
if *classifyFlag {
features = append(features, "Bedrock classification")
}
if *generatePoliciesFlag {
features = append(features, "IAM policy generation")
}

if len(features) > 0 {
fmt.Printf("Generating files with %s for %d service(s)\n\n", strings.Join(features, " and "), len(services))
} else {
fmt.Printf("Generating files for %d service(s)\n\n", len(services))
}

// Create output directory if it doesn't exist
if err := os.MkdirAll(*outputFlag, 0755); err != nil {
fmt.Printf("Error creating output directory: %v\n", err)
os.Exit(1)
}

totalOperations := 0
successfulServices := 0

for _, serviceName := range services {
serviceOps, err := extractor.ExtractDetailedOperationsFromService(serviceName, *classifyFlag)
if err != nil {
fmt.Printf("Error extracting operations for %s: %v\n", serviceName, err)
continue
}

if len(serviceOps.Operations) == 0 {
fmt.Printf("No operations found for %s\n", serviceName)
continue
}

outputFile := fmt.Sprintf("%s/%s-operations.json", *outputFlag, serviceName)
if writeErr := extractor.WriteServiceOperationsJSON(serviceOps, outputFile); writeErr != nil {
fmt.Printf("Error writing JSON file for %s: %v\n", serviceName, writeErr)
continue
}

fmt.Printf("%s: %d operations → %s\n", serviceName, len(serviceOps.Operations), outputFile)

if *generatePoliciesFlag {
policy, policyErr := extractor.GenerateSinglePolicy(serviceName, serviceOps.Operations)
if policyErr != nil {
fmt.Printf("Error generating policy for %s: %v\n", serviceName, policyErr)
} else {
if validateErr := extractor.ValidatePolicyJSON(*policy); validateErr != nil {
fmt.Printf("Warning: Policy validation failed for %s: %v\n", serviceName, validateErr)
}

policyFile := fmt.Sprintf("%s/%s-policy.json", *outputFlag, serviceName)
if writePolicyErr := extractor.WritePolicyJSON(policy, policyFile); writePolicyErr != nil {
fmt.Printf("Error writing policy file for %s: %v\n", serviceName, writePolicyErr)
} else {
fmt.Printf("%s: policy → %s\n", serviceName, policyFile)
}
}
}
totalOperations += len(serviceOps.Operations)
successfulServices++
}

fmt.Printf("\nSuccessfully generated JSON files for %d/%d services\n", successfulServices, len(services))
fmt.Printf("Total operations extracted: %d\n", totalOperations)
}
Loading