{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "InfraDesk Read-Only Scan Role \u2014 Default. Grants read-only access for AWS cost, resource, and utilization scanning. No delete, stop, modify, or create permissions. Remediation permissions are NOT included. Use infradesk-remediation-role.json separately only if enabling optional approval-based remediation.",
  "Parameters": {
    "ExternalId": {
      "Type": "String",
      "Description": "External ID for secure cross-account access",
      "Default": "infradesk-secure"
    },
    "UserId": {
      "Type": "String",
      "Description": "InfraDesk user ID"
    },
    "AccountNickname": {
      "Type": "String",
      "Description": "Friendly name for this AWS account",
      "Default": "My AWS Account"
    },
    "CallbackSecret": {
      "Type": "String",
      "Description": "Secret for callback verification",
      "Default": "infradesk-cf-secret"
    }
  },
  "Resources": {
    "InfraDeskRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": "InfraDeskRole",
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "AWS": "arn:aws:iam::171654889858:user/infradesk-service"
              },
              "Action": "sts:AssumeRole",
              "Condition": {
                "StringEquals": {
                  "sts:ExternalId": {
                    "Ref": "ExternalId"
                  }
                }
              }
            }
          ]
        },
        "Description": "InfraDesk read + safe remediation role (v4 - auto connect)",
        "MaxSessionDuration": 3600
      }
    },
    "InfraDeskCallbackLambdaRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": "InfraDeskCallbackLambdaRole",
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": "lambda.amazonaws.com"
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "Policies": [
          {
            "PolicyName": "InfraDeskCallbackLambdaLogsOnly",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                  ],
                  "Resource": "*"
                }
              ]
            },
            "_Note": "These permissions are for InfraDesk Lambda callback function to write its own execution logs only. They do not grant access to customer CloudWatch log groups or data."
          }
        ]
      }
    },
    "InfraDeskCallbackLambda": {
      "Type": "AWS::Lambda::Function",
      "DependsOn": [
        "InfraDeskRole",
        "InfraDeskCallbackLambdaRole"
      ],
      "Properties": {
        "FunctionName": {
          "Fn::Sub": "infradesk-callback-${UserId}"
        },
        "Runtime": "python3.12",
        "Handler": "index.handler",
        "Role": {
          "Fn::GetAtt": [
            "InfraDeskCallbackLambdaRole",
            "Arn"
          ]
        },
        "Timeout": 30,
        "Environment": {
          "Variables": {
            "INFRADESK_API_URL": "https://www.getinfradesk.com/api/cf-callback",
            "USER_ID": {
              "Ref": "UserId"
            },
            "EXTERNAL_ID": {
              "Ref": "ExternalId"
            },
            "ROLE_ARN": {
              "Fn::GetAtt": [
                "InfraDeskRole",
                "Arn"
              ]
            },
            "STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "REGION": {
              "Ref": "AWS::Region"
            },
            "ACCOUNT_NICKNAME": {
              "Ref": "AccountNickname"
            },
            "CALLBACK_SECRET": {
              "Ref": "CallbackSecret"
            }
          }
        },
        "Code": {
          "ZipFile": "import json\nimport os\nimport urllib.request\nimport cfnresponse\n\ndef handler(event, context):\n    print('Event:', json.dumps(event))\n    request_type = event.get('RequestType', '')\n    if request_type == 'Delete':\n        cfnresponse.send(event, context, cfnresponse.SUCCESS, {})\n        return\n    try:\n        payload = {\n            'userId': os.environ['USER_ID'],\n            'roleArn': os.environ['ROLE_ARN'],\n            'externalId': os.environ['EXTERNAL_ID'],\n            'region': os.environ['REGION'],\n            'stackName': os.environ['STACK_NAME'],\n            'accountName': os.environ['ACCOUNT_NICKNAME'],\n            'callbackSecret': os.environ['CALLBACK_SECRET'],\n        }\n        data = json.dumps(payload).encode('utf-8')\n        req = urllib.request.Request(\n            os.environ['INFRADESK_API_URL'],\n            data=data,\n            headers={'Content-Type': 'application/json', 'x-infradesk-signature': os.environ['CALLBACK_SECRET']},\n            method='POST'\n        )\n        with urllib.request.urlopen(req, timeout=25) as resp:\n            body = resp.read().decode('utf-8')\n            print('Callback response:', body)\n            cfnresponse.send(event, context, cfnresponse.SUCCESS, {'Message': 'Connected'})\n    except Exception as e:\n        print('Callback error:', str(e))\n        cfnresponse.send(event, context, cfnresponse.SUCCESS, {'Message': str(e)})\n"
        }
      }
    },
    "InfraDeskAutoConnect": {
      "Type": "AWS::CloudFormation::CustomResource",
      "DependsOn": [
        "InfraDeskCallbackLambda",
        "InfraDeskSafeRemediation"
      ],
      "Properties": {
        "ServiceToken": {
          "Fn::GetAtt": [
            "InfraDeskCallbackLambda",
            "Arn"
          ]
        },
        "UserId": {
          "Ref": "UserId"
        },
        "ExternalId": {
          "Ref": "ExternalId"
        },
        "Region": {
          "Ref": "AWS::Region"
        },
        "StackName": {
          "Ref": "AWS::StackName"
        }
      }
    }
  },
  "Outputs": {
    "RoleArn": {
      "Value": {
        "Fn::GetAtt": [
          "InfraDeskRole",
          "Arn"
        ]
      },
      "Description": "InfraDesk Role ARN"
    },
    "ExternalIdUsed": {
      "Value": {
        "Ref": "ExternalId"
      },
      "Description": "External ID configured"
    },
    "Region": {
      "Value": {
        "Ref": "AWS::Region"
      },
      "Description": "Region where stack was deployed"
    }
  },
  "Metadata": {
    "InfraDesk": {
      "RoleType": "ReadOnly",
      "Purpose": "Free scan \u2014 cost visibility, waste detection, utilization analysis",
      "RemediationIncluded": false,
      "WritePermissions": false,
      "Note": "This template contains zero write/delete/modify permissions on customer AWS resources. The only Create/Put permissions are logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents \u2014 these are for InfraDesk Lambda callback function to write its own execution logs only. They do not access or modify any customer resources."
    }
  }
}