AWS Users

At Reyki AI, security is our highest priority. We take painstaking measures to ensure that our customers’ infrastructure is never compromised by operating on the least privilege principle. At every stage of the process, we ensure that we utilize only the minimal permissions needed to operate our software.

Cross-Account Role

During the onboarding process, Reyki will ask you to create cross-account roles that enable us to access your AWS account with the minimum set of permissions we need to operate our software.

In a normal IAM role, an IAM user assumes an AWS identity with an access policy that determines the scope of the actions allowed to be taken by that user. For example, if a user assumes an IAM role with an access policy that only allows for “Describe” actions on EC2 services, that user will only be able to fetch metadata about the account’s EC2 instances. They will be blocked from modifying, creating, or deleting EC2 instances. Typically, these IAM roles are assumed by IAM users within the existing AWS account.

In a cross-account role, a user from an external AWS account assumes the role of an IAM user with the attached access policy in a different AWS account. These roles are administered through a trust policy that explicitly grants this permission:

{
  "Parameters": {
    "ReykiID": {
      "Description": "The Reyki customer ID linked to your AWS account.",
      "MinLength": "1",
      "Type": "String"
    },
    "ReykiExternalID": {
      "Description": "The Reyki external ID that authenticates your account.",
      "MinLength": "1",
      "Type": "String"
    },
    "ReykiRole": {
      "Description": "The Reyki IAM cross-account role used to authenticate with your account.",
      "MinLength": "1",
      "Type": "String"
    },
    "ReykiArn": {
      "Description": "The arn used to call back to Reyki.",
      "MinLength": "1",
      "Type": "String"
    },
    "ReykiSavingsNeeded": {
      "Description": "Boolean returning true if a savings estimate report is needed.",
      "MinLength": "1",
      "Type": "String"
    }    
  },
  "Resources" : {
    "CrossAccountRole" : {
      "Type" : "AWS::IAM::Role",
      "Properties" : {
        "AssumeRolePolicyDocument" : {
          "Statement" : [{
            "Effect" : "Allow",
            "Principal" : {
              "AWS" : {"Ref": "ReykiRole"}
            },
            "Action" : [
              "sts:AssumeRole"
            ],
            "Condition" : {
              "StringEquals" : {
                "sts:ExternalId" : {"Ref": "ReykiExternalID"}
              }
            }
          }]
        },
        "Path": "/",
        "Policies" : [
          {
            "PolicyName": "ReykiBillingReadOnly",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Action": [
                    "account:GetContactInformation",
                    "account:ListRegions",                  
                    "autoscaling:Describe*",
                    "budgets:Describe*",
                    "budgets:View*",
                    "ce:Get*",
                    "ce:Describe*",
                    "ce:List*",
                    "cloudwatch:GetMetricData",
                    "cur:Describe*",
                    "ec2:Describe*",
                    "elasticache:List*",
                    "elasticache:Describe*",                    
                    "es:Describe*",
                    "es:List*",                    
                    "pricing:DescribeServices",
                    "pricing:GetAttributeValues",
                    "pricing:GetProducts",
                    "organizations:Describe*",
                    "organizations:List*",
                    "rds:Describe*",
                    "rds:List*",
                    "redshift:Describe*",                    
                    "savingsplans:Describe*",
                    "savingsplans:List*",
                    "servicequotas:Get*",
                    "servicequotas:List*",                    
                    "support:*"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                }
              ]
            }
          },
          {
            "PolicyName": "ReykiCostAndUsageReport",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Action": [
                    "ce:Get*"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                },
                {
                  "Action": [
                    "cur:PutReportDefinition",
                    "cur:DescribeReportDefinitions"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                },
                {
                  "Action": [
                    "s3:CreateBucket",
                    "s3:PutBucketPolicy"
                  ],
                  "Resource": "arn:aws:s3:::cur-shared-with-reyki-*",
                  "Effect": "Allow"
                }
              ]
            }
          },                  
          {
            "PolicyName": "ReykiRoleEditor",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Sid": "RoleEditor",
                  "Effect": "Allow",
                  "Action": [
                      "iam:ListRolePolicies",
                      "iam:ListAttachedRolePolicies",
                      "iam:CreatePolicyVersion",
                      "iam:PutRolePolicy",
                      "iam:GetRole",
                      "iam:UpdateRole",
                      "iam:PutRolePermissionsBoundary",
                      "iam:CreatePolicy"
                  ],
                  "Resource": [
                      "arn:aws:iam::*:role/Reyki*CrossAccountRole*"
                  ]
                }
              ]
            }
          }, 
          {
            "PolicyName": "ReykiObjectStorageAutopilot",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Sid": "CloudWatchExporter",
                  "Action": [
                    "tag:GetResources",
                    "cloudwatch:GetMetricData",
                    "cloudwatch:GetMetricStatistics",
                    "cloudwatch:ListMetrics",
                    "apigateway:GET",
                    "aps:ListWorkspaces",
                    "autoscaling:DescribeAutoScalingGroups",
                    "dms:DescribeReplicationInstances",
                    "dms:DescribeReplicationTasks",
                    "ec2:DescribeTransitGatewayAttachments",
                    "ec2:DescribeSpotFleetRequests",
                    "shield:ListProtections",
                    "storagegateway:ListGateways",
                    "storagegateway:ListTagsForResource"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                },
                {
                  "Sid": "S3StorageLens",
                  "Effect": "Allow",
                  "Action": [
                      "s3:ListStorageLensConfigurations",
                      "s3:GetStorageLensConfiguration",
                      "s3:DeleteStorageLensConfiguration",
                      "s3:DeleteStorageLensConfigurationTagging",
                      "s3:UpdateStorageLensGroup",
                      "s3:PutStorageLensConfigurationTagging",
                      "s3:PutStorageLensConfiguration",
                      "s3:GetStorageLensConfigurationTagging",
                      "s3:*StorageLens*"
                  ],
                  "Resource": "*"
                },
                {
                  "Sid": "S3LifecycleManagement",
                  "Action": [
                    "s3:*Lifecycle*",
                    "s3:*Notification*"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                }
              ]
            }
          }, 
          {
            "PolicyName": "ReykiAutopilot",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Action": [
                    "application-autoscaling:Describe*",
                    "aws-portal:ViewBilling",
                    "aws-portal:ViewUsage",
                    "cloudwatch:Describe*",
                    "cloudwatch:Get*",
                    "cloudwatch:List*",
                    "consolidatedbilling:List*",
                    "consolidatedbilling:Get*",        
                    "cur:*",
                    "ec2:AcceptReservedInstancesExchangeQuote",
                    "ec2:CreateTags",
                    "ec2:CancelReservedInstancesListing",
                    "ec2:CreateReservedInstancesListing",
                    "ec2:DeleteQueuedReservedInstances",
                    "ec2:GetCapacityReservationUsage",
                    "ec2:GetReservedInstancesExchangeQuote",
                    "ec2:ModifyReservedInstances",
                    "ec2:PurchaseHostReservation",
                    "ec2:PurchaseReservedInstancesOffering",
                    "ecs:Describe*",
                    "ecs:List*",
                    "eks:Describe*",
                    "eks:List*",
                    "elasticache:List*",
                    "elasticache:Describe*",        
                    "elasticache:PurchaseReservedCacheNodesOffering",
                    "es:PurchaseReservedInstanceOffering",        
                    "organizations:AcceptHandshake",
                    "redshift:Describe*",
                    "redshift:GetReservedNodeExchangeConfigurationOptions",
                    "redshift:GetReservedNodeExchangeOfferings",
                    "rds:PurchaseReservedDbInstancesOffering",
                    "redshift:PurchaseReservedNodeOffering",
                    "redshift:AcceptReservedNodeExchange",
                    "servicequotas:RequestServiceQuotaIncrease",
        "s3:Create*",
                    "tag:Get*",
                    "transfer:Describe*",
                    "transfer:List*"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                }
              ]
            }
          }
        ]
      }
    },
    "ReykiPingResource" : {
      "Type" : "Custom::ReykiPingResource",
      "DeletionPolicy" : "Retain",
      "Version" : "1.0",
      "Properties" : {
        "ServiceToken" : {
          "Ref": "ReykiArn"
        },
        "RoleArn" : {
          "Fn::GetAtt": [ "CrossAccountRole", "Arn" ]
        },
        "ReykiID" : {
          "Ref": "ReykiID"
        },
        "ExternalID": {
          "Ref": "ReykiExternalID"
        },
        "AccountID": {
          "Ref": "AWS::AccountId"
        },
        "ReykiSavingsNeeded": {
          "Ref": "ReykiSavingsNeeded"
        }
      }
    }
  },
  "Outputs" : {
    "RoleArn" : {
      "Value" : {"Fn::GetAtt": [ "CrossAccountRole", "Arn" ]},
      "Description" : "The ARN value of the Cross-Account Role with IAM read-only permissions. Add this ARN value to Reyki."
    }
  }
}

Data Storage

Reyki retrieves and stores cost and usage metadata through the permissions granted by the Cross-Account Roles. Specifically, we store the following:

  • All spend and savings data dating back to 1 year for the read-only dashboard.

  • All spend and savings data starting from the date the customer joins the Reyki organization.

  • Reserved instance and savings plan information, including spend commitments and utilization.

  • EC2 metadata, including region, instance type and family, platform, and purchase type.

All data is deleted when a customer deactivates their account in compliance with GDPR regulations.

AWS Organization Security Principles

In general, we follow the best practices recommended by AWS Well-Architected Framework to ensure the security of our AWS Organization. These principles include the following:

  • Our AWS root account is never accessed; we only interact with the organization through IAM accounts.

  • Our root account requires hardware MFA to gain access.

  • All IAM user accounts have multi-factor authentication enabled and are assigned roles based on the principle of least functionality.

  • No Service Control Policies affecting member accounts are implemented, so there is no risk of blocking access to resources for any of our child accounts.

  • We've enabled AWS GuardDuty for all available services (S3, EKS, EC2, RDS, Lambda).

  • We've implemented AWS Control Tower's strongly recommended controls for our root user account.

Last updated