使用AWS CUR V2账单分析Kiro用户的Credit用量

一、背景

由于目前(2026-01)Kiro的控制台Dashboard暂时不能显示单个用户的Credit使用情况,因此建议通过计费系统进行查询。本文讲述如何使用Athena查询CUR V2获得Kiro用户的Credit使用情况。

1、Kiro计费模式

Kiro目前提供三个级别的订阅,分别是:

  • Pro: 内含 1000 Credit;
  • Pro+:内含 2000 Credit;
  • Power:内含 10000 Credit;

以上,超出套餐内的使用量之后,额外消耗的Credit按照$0.04/credit计费。

官方对Credit的解释如下:https://kiro.dev/pricing/#what-is-a-credit

Credit(积分)是响应用户提示的工作单位。简单的提示可能消耗不到 1 个积分。
更复杂的提示,例如执行规格任务,通常会消耗超过 1 个积分。
此外,不同的模型以不同的速率消耗积分,使用Sonnet 4 执行提示比使用 Auto 执行消耗更多积分。

由于目前(2026-01)Kiro的控制台Dashboard暂时不能显示单个用户的Credit使用情况,因此建议通过AWS云的账单系统的CUR数据进行查询。

2、CUR V2介绍

AWS CUR V2(Cost and Usage Report 2.0) 是 AWS 在 2023 年 re:Invent 发布的新版成本和用量报告,为用户给出完整的账单计费原始数据并保存到S3存储桶中。CUR V2支持csv(gzip压缩)或者parquet格式,可以使用Athena服务的SQL语句进行查询。

二、创建CUR V2

1、创建S3存储桶

创建一个用于保存CUR数据的存储桶,放在美东1(us-east-1)区域。存储桶设置全默认即可。

2、开启CUR V2

进入AWS控制台,进入Billing and Cost Management服务,在左侧菜单下,找到菜单项Cost and Usage Analysis,再从中找到Data Exports,点击进去。

点击Create创建按钮,选择如下:

  • 类型选择Standard data export
  • 名字自行拟定
  • Data table content settings选择CUR 2.0
  • Billing view设置不用修改
  • Additional export content设置不用修改
  • Time granularity选择为dailyHourly均可
  • SQL statement默认已经选中了所有列,不用修改
  • Data export delivery options的Compression type and file format选择Parquet - Parquet
  • Data export storage settings位置输入上一步创建的S3存储桶和路径,建议在存储桶根目录下增加子目录(prefix),例如s3://cur-v2-myaws/cur-export,有子目录便于未来创建Athena表格

其他设置无须修改,点击创建。

3、等待24-48小时生成第一批CUR数据

注意:

  • CUR有较大延迟,通常在1天以上,创建CUR时候有个时间颗粒度选项,hourly或者daily,这表示CUR明细的颗粒度,但不意味着选hourly就是每小时推送CUR数据。CUR数据是按天推送的
  • CUR只记录打开一刻起的数据。例如本月15日启用了CUR,那么17日左右开始生成15-16日的数据,15日之前的将不会提供CUR

三、使用Athena查询CUR数据获取Kiro使用量

在等待24-48小时后,CUR有了数据,继续创建表格做查询。

1、使用Athena创建表

进入Athena服务,在默认database下执行如下SQL创建表。注意替换以下SQL中的S3存储桶的路径’s3://cur-lxy-us-east-1/cur-v2/cur-v2/data/‘为实际的CUR保存目录下自动生成的data目录。你可以从S3存储桶服务界面去查看目录,直到发现最后一层data目录。

CREATE EXTERNAL TABLE `cur-v2data`(
  `bill_bill_type` string, 
  `bill_billing_entity` string, 
  `bill_billing_period_end_date` timestamp, 
  `bill_billing_period_start_date` timestamp, 
  `bill_invoice_id` string, 
  `bill_invoicing_entity` string, 
  `bill_payer_account_id` string, 
  `bill_payer_account_name` string, 
  `cost_category` map<string,string>, 
  `discount` map<string,double>, 
  `discount_bundled_discount` double, 
  `discount_total_discount` double, 
  `identity_line_item_id` string, 
  `identity_time_interval` string, 
  `line_item_availability_zone` string, 
  `line_item_blended_cost` double, 
  `line_item_blended_rate` string, 
  `line_item_currency_code` string, 
  `line_item_legal_entity` string, 
  `line_item_line_item_description` string, 
  `line_item_line_item_type` string, 
  `line_item_net_unblended_cost` double, 
  `line_item_net_unblended_rate` string, 
  `line_item_normalization_factor` double, 
  `line_item_normalized_usage_amount` double, 
  `line_item_operation` string, 
  `line_item_product_code` string, 
  `line_item_resource_id` string, 
  `line_item_tax_type` string, 
  `line_item_unblended_cost` double, 
  `line_item_unblended_rate` string, 
  `line_item_usage_account_id` string, 
  `line_item_usage_account_name` string, 
  `line_item_usage_amount` double, 
  `line_item_usage_end_date` timestamp, 
  `line_item_usage_start_date` timestamp, 
  `line_item_usage_type` string, 
  `pricing_currency` string, 
  `pricing_lease_contract_length` string, 
  `pricing_offering_class` string, 
  `pricing_public_on_demand_cost` double, 
  `pricing_public_on_demand_rate` string, 
  `pricing_purchase_option` string, 
  `pricing_rate_code` string, 
  `pricing_rate_id` string, 
  `pricing_term` string, 
  `pricing_unit` string, 
  `product` map<string,string>, 
  `product_comment` string, 
  `product_fee_code` string, 
  `product_fee_description` string, 
  `product_from_location` string, 
  `product_from_location_type` string, 
  `product_from_region_code` string, 
  `product_instance_family` string, 
  `product_instance_type` string, 
  `product_instancesku` string, 
  `product_location` string, 
  `product_location_type` string, 
  `product_operation` string, 
  `product_pricing_unit` string, 
  `product_product_family` string, 
  `product_region_code` string, 
  `product_servicecode` string, 
  `product_sku` string, 
  `product_to_location` string, 
  `product_to_location_type` string, 
  `product_to_region_code` string, 
  `product_usagetype` string, 
  `reservation_amortized_upfront_cost_for_usage` double, 
  `reservation_amortized_upfront_fee_for_billing_period` double, 
  `reservation_availability_zone` string, 
  `reservation_effective_cost` double, 
  `reservation_end_time` string, 
  `reservation_modification_status` string, 
  `reservation_net_amortized_upfront_cost_for_usage` double, 
  `reservation_net_amortized_upfront_fee_for_billing_period` double, 
  `reservation_net_effective_cost` double, 
  `reservation_net_recurring_fee_for_usage` double, 
  `reservation_net_unused_amortized_upfront_fee_for_billing_period` double, 
  `reservation_net_unused_recurring_fee` double, 
  `reservation_net_upfront_value` double, 
  `reservation_normalized_units_per_reservation` string, 
  `reservation_number_of_reservations` string, 
  `reservation_recurring_fee_for_usage` double, 
  `reservation_reservation_a_r_n` string, 
  `reservation_start_time` string, 
  `reservation_subscription_id` string, 
  `reservation_total_reserved_normalized_units` string, 
  `reservation_total_reserved_units` string, 
  `reservation_units_per_reservation` string, 
  `reservation_unused_amortized_upfront_fee_for_billing_period` double, 
  `reservation_unused_normalized_unit_quantity` double, 
  `reservation_unused_quantity` double, 
  `reservation_unused_recurring_fee` double, 
  `reservation_upfront_value` double, 
  `resource_tags` map<string,string>, 
  `savings_plan_amortized_upfront_commitment_for_billing_period` double, 
  `savings_plan_end_time` string, 
  `savings_plan_instance_type_family` string, 
  `savings_plan_net_amortized_upfront_commitment_for_billing_period` double, 
  `savings_plan_net_recurring_commitment_for_billing_period` double, 
  `savings_plan_net_savings_plan_effective_cost` double, 
  `savings_plan_offering_type` string, 
  `savings_plan_payment_option` string, 
  `savings_plan_purchase_term` string, 
  `savings_plan_recurring_commitment_for_billing_period` double, 
  `savings_plan_region` string, 
  `savings_plan_savings_plan_a_r_n` string, 
  `savings_plan_savings_plan_effective_cost` double, 
  `savings_plan_savings_plan_rate` double, 
  `savings_plan_start_time` string, 
  `savings_plan_total_commitment_to_date` double, 
  `savings_plan_used_commitment` double, 
  `split_line_item_actual_usage` double, 
  `split_line_item_net_split_cost` double, 
  `split_line_item_net_unused_cost` double, 
  `split_line_item_parent_resource_id` string, 
  `split_line_item_public_on_demand_split_cost` double, 
  `split_line_item_public_on_demand_unused_cost` double, 
  `split_line_item_reserved_usage` double, 
  `split_line_item_split_cost` double, 
  `split_line_item_split_usage` double, 
  `split_line_item_split_usage_ratio` double, 
  `split_line_item_unused_cost` double)
PARTITIONED BY ( 
  `billing_period` string)
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
  's3://cur-lxy-us-east-1/cur-v2/cur-v2/data/'
TBLPROPERTIES (
  'classification'='parquet', 
  'compressionType'='none', 
  'partition_filtering.enabled'='true', 
  'typeOfData'='file')

随后即可在Athena默认数据库下,创建了名为cur-v2data的表。

2、查询使用量

(1) 查询本月所有和Kiro相关的计费条目(含Credit使用和订阅)

在Athena上运行如下SQL

-- 查询本月所有和Kiro相关的数据
SELECT 
    identity_time_interval as time_range,
    line_item_operation as cost_type,
    product_usagetype as usage_type,
    line_item_line_item_description as description,
    product_sku as sku,
    line_item_usage_amount as usage_amount,
    line_item_resource_id as user_id,
    line_item_blended_cost as blended_cost,
    line_item_unblended_cost as unblended_cost
FROM "default"."cur-v2data"
WHERE
    billing_period = '2026-01'
    AND product_location = 'US East (N. Virginia)'
    AND line_item_product_code = 'Kiro'
Order by time_range, usage_type
LIMIT 20;

注意:以上SQL查询结果中,user_id是对应的Kiro订阅时候的IAM Identity Center中的user的id。这个id不是用户名也不是邮箱,下文可通过关联查询获取用户真实姓名或邮箱。

(2) 查询本月内所有用户的Kiro Credit使用累计

WITH user_plans AS (
    SELECT DISTINCT
        SPLIT_PART(line_item_resource_id, 'user/', 2) as user_id,
        CASE
            WHEN product_usagetype LIKE '%Pro+%' THEN 'Pro+'
            WHEN product_usagetype LIKE '%Power%' THEN 'Power'
            WHEN product_usagetype LIKE '%Pro%' THEN 'Pro'
        END as subscription_plan
    FROM "default"."cur-v2data"
    WHERE
        billing_period = '2026-01'
        AND line_item_product_code = 'Kiro'
        AND line_item_operation = 'monthly-subscription'
)
SELECT
    p.subscription_plan,
    CASE
        WHEN p.subscription_plan = 'Pro' THEN 1000
        WHEN p.subscription_plan = 'Pro+' THEN 2000
        WHEN p.subscription_plan = 'Power' THEN 10000
    END as plan_credits,
    p.user_id,
    SUM(c.line_item_usage_amount) as total_credits
FROM "default"."cur-v2data" c
JOIN user_plans p ON SPLIT_PART(c.line_item_resource_id, 'user/', 2) = p.user_id
WHERE
    c.billing_period = '2026-01'
    AND c.line_item_product_code = 'Kiro'
    AND c.line_item_operation = 'Credits'
GROUP BY
    p.subscription_plan,
    p.user_id
ORDER BY
    CASE
        WHEN p.subscription_plan = 'Pro' THEN 1
        WHEN p.subscription_plan = 'Pro+' THEN 2
        WHEN p.subscription_plan = 'Power' THEN 3
    END,
    p.user_id

返回数据格式如下:

#	subscription_plan	plan_credits	user_id	total_credits
1	Pro	1000	843884c8-00c1-7046-e4e8-7ba5acc6cfc7	1.7210808227999999

注意:以上SQL查询结果中,user_id是对应的Kiro订阅时候的IAM Identity Center中的user的id。这个id不是用户名也不是邮箱,下文可通过关联查询获取用户真实姓名或邮箱。

(3) 查询哪些用户超过了订阅的Plan的总和(如果没有超额则显示为空)

WITH user_plans AS (
    SELECT DISTINCT
        SPLIT_PART(line_item_resource_id, 'user/', 2) as user_id,
        CASE
            WHEN product_usagetype LIKE '%Pro+%' THEN 'Pro+'
            WHEN product_usagetype LIKE '%Power%' THEN 'Power'
            WHEN product_usagetype LIKE '%Pro%' THEN 'Pro'
        END as subscription_plan
    FROM "default"."cur-v2data"
    WHERE
        billing_period = '2026-01'
        AND line_item_product_code = 'Kiro'
        AND line_item_operation = 'monthly-subscription'
),
user_usage AS (
    SELECT
        p.subscription_plan,
        CASE
            WHEN p.subscription_plan = 'Pro' THEN 1000
            WHEN p.subscription_plan = 'Pro+' THEN 2000
            WHEN p.subscription_plan = 'Power' THEN 10000
        END as plan_credits,
        p.user_id,
        SUM(c.line_item_usage_amount) as total_credits
    FROM "default"."cur-v2data" c
    JOIN user_plans p ON SPLIT_PART(c.line_item_resource_id, 'user/', 2) = p.user_id
    WHERE
        c.billing_period = '2026-01'
        AND c.line_item_product_code = 'Kiro'
        AND c.line_item_operation = 'Credits'
    GROUP BY
        p.subscription_plan,
        p.user_id
)
SELECT
    subscription_plan,
    plan_credits,
    user_id,
    total_credits,
    total_credits - plan_credits as overage
FROM user_usage
WHERE total_credits > plan_credits
ORDER BY
    CASE
        WHEN subscription_plan = 'Pro' THEN 1
        WHEN subscription_plan = 'Pro+' THEN 2
        WHEN subscription_plan = 'Power' THEN 3
    END,
    user_id

如果有用户超额,则显示用户清单,如果没有超额,则显示为空。

注意:以上SQL查询结果中,user_id是对应的Kiro订阅时候的IAM Identity Center中的user的id。这个id不是用户名也不是邮箱,下文可通过关联查询获取用户真实姓名或邮箱。

四、建立Kiro的用户名和用户ID的映射关系

本文采用从IAM Identity Center手工导出一个最新用户清单的办法,另外新建一个Athena表,然后做联合查询完成userid和用户名的对应关系。如果需要的话,稍微修改下,即可完成用户邮箱和用户id的映射。

1、使用AWSCLI查询IAM Identity Center上的用户ID映射关系

在配置了AWSCLI的环境上,使用如下命令,查询AWS当前使用的SSO的Instance ID。

aws sso-admin list-instances --region us-east-1

返回结果如下:

{
    "Instances": [
        {
            "InstanceArn": "arn:aws:sso:::instance/ssoins-72236887c48a0b06",
            "IdentityStoreId": "d-9066195b8c",
            "OwnerAccountId": "133129065110",
            "CreatedDate": "2025-12-22T11:36:00.192000+08:00",
            "Status": "ACTIVE"
        }
    ]
}

以上信息中的IdentityStoreId就是我们需要的信息。将这个ID复制下来,构建如下AWSCLI命令,导出用户清单。

aws identitystore list-users \
  --identity-store-id d-9066195b8c \
  --region us-east-1 \
  --query 'Users[*].{Username:UserName,UserId:UserId}' \
  --output json | jq -c '.[]' > user-list.jsonl

这个命令会将当前IAM Identity Center上的所有用户输出到一个JSON List文件。如果用户数量较多,AWSCLI会自动分批获取,时间会比较长。

生成的jsonl文件格式如下。

{"Username":"user01","UserId":"843884c8-00c1-7046-e4e8-7ba5acc6cfc7"}
{"Username":"user02","UserId":"04d86408-4001-7047-01d1-077885ab54fa"}

现在在执行AWSCLI的本地环境中获得了user-list.jsonl文件。接下来将这个文件导入到Athena的表中方便SQL查询。

2、在Athena内创建用户名和用户ID映射表

将以上文件上传到S3存储桶,例如路径是s3://cur-lxy-us-east-1/user-list/。然后登陆到AWS控制台,进入Athena服务,执行如下命令创建新表

CREATE EXTERNAL TABLE default.identity_center_users (
  Username string,
  UserId string
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
  'dots.in.keys' = 'false',
  'case.insensitive' = 'true',
  'mapping' = 'true'
)
LOCATION 's3://cur-lxy-us-east-1/user-list/'

由此在Athena的default数据库内,创建了一个名为identity_center_users的表。

创建表完毕后,查询测试:

SELECT * FROM "default"."identity_center_users" limit 10;

可看到返回结果正常。

#	username	userid
1	user01		843884c8-00c1-7046-e4e8-7ba5acc6cfc7
2	user02		04d86408-4001-7047-01d1-077885ab54fa

五、将CUR V2查询结果和用户映射表关联

以上两个步骤,分别有了Kiro用户使用Credit情况和Kiro用户名映射表两种类型的数据,由此可以拼接在一起。

1、查询所有用户的Credit使用情况(拼接用户名)

WITH user_plans AS (
    SELECT DISTINCT
        SPLIT_PART(line_item_resource_id, 'user/', 2) as user_id,
        CASE
            WHEN product_usagetype LIKE '%Pro+%' THEN 'Pro+'
            WHEN product_usagetype LIKE '%Power%' THEN 'Power'
            WHEN product_usagetype LIKE '%Pro%' THEN 'Pro'
        END as subscription_plan
    FROM "default"."cur-v2data"
    WHERE
        billing_period = '2026-01'
        AND line_item_product_code = 'Kiro'
        AND line_item_operation = 'monthly-subscription'
)
SELECT
    p.subscription_plan,
    CASE
        WHEN p.subscription_plan = 'Pro' THEN 1000
        WHEN p.subscription_plan = 'Pro+' THEN 2000
        WHEN p.subscription_plan = 'Power' THEN 10000
    END as plan_credits,
    u.username,
    SUM(c.line_item_usage_amount) as total_credits
FROM "default"."cur-v2data" c
JOIN user_plans p ON SPLIT_PART(c.line_item_resource_id, 'user/', 2) = p.user_id
LEFT JOIN "default"."identity_center_users" u ON p.user_id = u.userid
WHERE
    c.billing_period = '2026-01'
    AND c.line_item_product_code = 'Kiro'
    AND c.line_item_operation = 'Credits'
GROUP BY
    p.subscription_plan,
    u.username
ORDER BY
    CASE
        WHEN p.subscription_plan = 'Pro' THEN 1
        WHEN p.subscription_plan = 'Pro+' THEN 2
        WHEN p.subscription_plan = 'Power' THEN 3
    END,
    u.username

返回结果如下:

#	subscription_plan	plan_credits	username	total_credits
1	Pro	1000	user01	1.7210808227999999

2、查询超过Plan内Credit使用的用户(拼接用户名,如果没有则显示空)

WITH user_plans AS (
    SELECT DISTINCT
        SPLIT_PART(line_item_resource_id, 'user/', 2) as user_id,
        CASE
            WHEN product_usagetype LIKE '%Pro+%' THEN 'Pro+'
            WHEN product_usagetype LIKE '%Power%' THEN 'Power'
            WHEN product_usagetype LIKE '%Pro%' THEN 'Pro'
        END as subscription_plan
    FROM "default"."cur-v2data"
    WHERE
        billing_period = '2026-01'
        AND line_item_product_code = 'Kiro'
        AND line_item_operation = 'monthly-subscription'
),
user_usage AS (
    SELECT
        p.subscription_plan,
        CASE
            WHEN p.subscription_plan = 'Pro' THEN 1000
            WHEN p.subscription_plan = 'Pro+' THEN 2000
            WHEN p.subscription_plan = 'Power' THEN 10000
        END as plan_credits,
        p.user_id,
        SUM(c.line_item_usage_amount) as total_credits
    FROM "default"."cur-v2data" c
    JOIN user_plans p ON SPLIT_PART(c.line_item_resource_id, 'user/', 2) = p.user_id
    WHERE
        c.billing_period = '2026-01'
        AND c.line_item_product_code = 'Kiro'
        AND c.line_item_operation = 'Credits'
    GROUP BY
        p.subscription_plan,
        p.user_id
)
SELECT
    uu.subscription_plan,
    uu.plan_credits,
    u.username,
    uu.total_credits,
    uu.total_credits - uu.plan_credits as overage
FROM user_usage uu
LEFT JOIN "default"."identity_center_users" u ON uu.user_id = u.userid
WHERE uu.total_credits > uu.plan_credits
ORDER BY
    CASE
        WHEN uu.subscription_plan = 'Pro' THEN 1
        WHEN uu.subscription_plan = 'Pro+' THEN 2
        WHEN uu.subscription_plan = 'Power' THEN 3
    END,
    u.username

如果所有用户都没有超额使用,则查询结果为空。

六、参考文档

https://kiro.dev/docs/enterprise/monitor-and-track/dashboard/#dashboard-metrics

注:本文SQL由Kiro生成

-完-


最后修改于 2026-01-27