Code Monkey home page Code Monkey logo

aws-samples / aws-iam-identity-center-extensions Goto Github PK

View Code? Open in Web Editor NEW
61.0 8.0 23.0 2.86 MB

This solution is intended for enterprises that need a streamlined way of managing user access to their AWS accounts. Using this solution, your identity and access management teams can extend AWS SSO functionality by automating common access management and governance use cases

License: MIT License

JavaScript 1.87% TypeScript 98.13%
aws-sso aws-sso-for-enterprise

aws-iam-identity-center-extensions's Introduction

AWS IAM Identity Center Extensions For Enterprise

Table of Contents

Overview

High level design

AWS IAM Identity Center Extensions for Enterprise simplifies the process to manage user access to AWS accounts with AWS IAM Identity Center by extending the AWS IAM Identity Center API.

Instead of separately managing AWS IAM Identity Center permission sets and account assignments, you can use this solution to describe permission sets with one API call per set. Like with permission sets, you can also define and implement account assignments at a global level, an organizational unit level or an account tag level. The solution ensures your defined permissions are rolled out across the entire AWS Organization, and that they are updated as you change your organization.

This solution can be used by your identity and access management team to simplify user access provisioning at scale, either via a RESTFul API or by defining and setting objects with your permissions descriptions in an S3 bucket. This enables you to integrate with upstream identity management systems you have in your organization.

Get started with the deployment!

Features

The Composite Permission Set API

This solution provides a composite API for managing permission set lifecycles, allowing you to:

  • Create a permission set object including attributes and policies in a single call
  • Update parts or all of a permission set object in a single call with a friendly name
  • Delete a complete permission set in a single call with a friendly name
  • Based on a configuration parameter, use either an S3 based interface or a RESTful API to upload permission set object as a whole
  • Enforce the "cannot delete" constraint when a permission set is being referenced in an account assignment
Example payload to create a permission set

{
  "action": "create",
  "permissionSetData": {
    "permissionSetName": "CloudOperator-ps",
    "sessionDurationInMinutes": "240",
    "relayState": "https://{{region}}.console.aws.amazon.com/console/home?region={{region}}#",
    "tags": [
      {
        "Key": "versionid",
        "Value": "01"
      },
      {
        "Key": "team",
        "Value": "CloudOperators"
      }
    ],
    "managedPoliciesArnList": [
      "arn:aws:iam::aws:policy/job-function/SystemAdministrator",
      "arn:aws:iam::aws:policy/job-function/NetworkAdministrator"
    ],
    "inlinePolicyDocument": {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Action": [
            "iam:AddRoleToInstanceProfile",
            "iam:CreateInstanceProfile",
            "iam:CreatePolicy",
            "iam:CreatePolicyVersion",
            "iam:DeleteInstanceProfile",
            "iam:DeletePolicy",
            "iam:DeleteRole",
            "iam:PassRole",
            "iam:UpdateRole",
            "iam:DeleteRolePermissionsBoundary",
            "iam:UpdateRoleDescription",
            "iam:RemoveRoleFromInstanceProfile"
          ],
          "Resource": [
            "arn:aws:iam::*:role/Application_*",
            "arn:aws:iam::*:policy/Application_*",
            "arn:aws:iam::*:instance-profile/Application_*"
          ],
          "Effect": "Allow",
          "Sid": "AllowOtherIAMActions"
        },
        {
          "Action": ["iam:List*", "iam:Generate*", "iam:Get*", "iam:Simulate*"],
          "Resource": "*",
          "Effect": "Allow",
          "Sid": "AllowReadIAMActions"
        }
      ]
    },
    "customerManagedPoliciesList": [
      {
        "Name": "cmp-1",
        "Path": "/cmp/1/"
      },
      {
        "Name": "cmp-2",
        "Path": "/cmp/2/"
      },
      {
        "Name": "cmp-3"
      }
    ],
    "permissionsBoundary": {
      "ManagedPolicyArn": "arn:aws:iam::aws:policy/job-function/NetworkAdministrator"
    }
  }
}

Example payload to update a permission set

{
  "action": "update",
  "permissionSetData": {
    "permissionSetName": "CloudOperator-ps",
    "sessionDurationInMinutes": "420",
    "relayState": "https://{{region}}.console.aws.amazon.com/console/home?region={{region}}#",
    "tags": [
      {
        "Key": "versionid",
        "Value": "02"
      },
      {
        "Key": "team",
        "Value": "CloudOperators"
      }
    ],
    "managedPoliciesArnList": [
      "arn:aws:iam::aws:policy/job-function/SystemAdministrator",
      "arn:aws:iam::aws:policy/job-function/NetworkAdministrator",
      "arn:aws:iam::aws:policy/AWSHealthFullAccess"
    ],
    "inlinePolicyDocument": {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Action": ["iam:List*", "iam:Generate*", "iam:Get*", "iam:Simulate*"],
          "Resource": "*",
          "Effect": "Allow",
          "Sid": "AllowReadIAMActions"
        }
      ]
    },
    "customerManagedPoliciesList": [
      {
        "Name": "cmp-1",
        "Path": "/cmp/1/"
      },
      {
        "Name": "cmp-2",
        "Path": "/cmp/2/"
      },
      {
        "Name": "cmp-3"
      }
    ],
    "permissionsBoundary": {
      "CustomerManagedPolicyReference": {
        "Name": "cmp-pb",
        "Path": "/cmp/pb/"
      }
    }
  }
}

Example payload to delete a permission set

{
  "action": "delete",
  "permissionSetData": {
    "permissionSetName": "CloudOperator-ps"
  }
}

Enterprise friendly account assignment life cycle

This solution enables enterprise friendly account assignment lifecycles through the following features:

  • Using users/groups as the mechanism for the principal type
  • Friendly names for users/groups and permission sets when creating account assignments
  • Based on the configuration parameter, you can use either an S3 based interface/ Rest API interface to create/delete account assignments
  • Create & delete account assignments with scope set to account, root, ou_id or account_tag
  • Using the entity value passed in the payload, the solution calculates the account list and processes the account assignment operations on all the accounts automatically
  • When using an ou_id scope type, the solution optionally provides nested OU support as well. This behaviour could be configured by setting SupportNestedOU to true in your environment configuration file. When configured, the solution discovers all the children under a specified ou_id traversing the complete tree and assigning the account assignment to every single account under the tree.

NOTE: Permission sets and user/group assignments cannot be applied to the Organization Main account (also known as the Master Payer) due to a design constraint of the AWS API. There is no available mechanism to programmatically manage the permission sets and user/group assignments of the Organization Main account.

Example payload to provision permission set CloudOperator-ps for all accounts in your organization and provide access to team-CloudOperators user group

{
  "action": "create",
  "linkData": "root%all%CloudOperator-ps%team-CloudOperators%GROUP%ssofile"
}

Example payload to provision permission set SecurityAuditor-ps for all accounts in your organization unit with ID ou-id12345 and provide access to team-SecurityAuditors user group

{
  "action": "create",
  "linkData": "ou_id%ou-id12345%SecurityAuditor-ps%team-SecurityAuditors%GROUP%ssofile"
}

Example payload to provision permission set DataScientist-ps for all accounts that have tagkey team set to value DataScientists and provide access to team-DataScientists user group

{
  "action": "create",
  "linkData": "account_tag%team^DataScientists%DataScientist-ps%team-DataScientists%GROUP%ssofile"
}

Example payload to provision permission set Billing-ps for account 123456789012 and provide access to team-Accountants user group

{
  "action": "create",
  "linkData": "account%123456789012%Billing-ps%team-Accountants%GROUP%ssofile"
}

Example payload to provision permission set Breakglass-ps for all accounts in your organization and provide access to break-glass user

{
  "action": "create",
  "linkData": "root%all%Breakglass-ps%break-glass%USER%ssofile"
}


Automated access change management for root, ou_id and account_tag scopes

The solution provides automated change access management through the following features:

  • If an account assignment has been created through the solution with scope set to root, and if a new account has been created at a later time, this new account is automatically provisioned with the account assignment.
  • If an account assignment has been created through the solution with scope set to ou_id, and an existing account moves out of this ou, this account assignment is automatically deleted from the account by the solution. If a new account is moved in to the ou, this account assignment is automatically created for the account by the solution.
  • The solution also supports nested OU behaviour for automated access change management. This behaviour could be configured by setting SupportNestedOU to true in your environment configuration file. If the nested OU support is configured, when an account moves from a source OU to a destination OU, the solution discovers all the parents of the source OU and destination OU until root , to determine the list of account assignments that need to be removed/added automatically.
  • If an account assignment has been created through the solution with scope set to account_tag, and an account is updated with this tag key value at a later time, this account assignment is automatically created for the new account by the solution. Additionally, when this tag key value is removed from the account/when this tag key is updated to a different value on the account at a later time, this account assignment is automatically deleted from the account by the solution.

Import existing AWS IAM Identity Center access entitlements for management through the solution

  • The solution enables a one-time import of existing AWS IAM Identity Center access entitlements for management through the solution
  • Based on the ImportCurrentSSOConfiguration flag in the configuration file, the solution would import all existing permission sets and account assignments so that they could be updated/deleted through the solution interfaces
  • The solution ensures that all related attributes of permission sets/account assignments are imported in a format that would allow you to manage them through the solution interfaces
  • All account assignments would be imported as account scope types
  • While the solution triggers an automatic import one-time through the pipeline, once enabled the env-importCurrentConfigSM state machine in your AWS IAM Identity Center account and AWS IAM Identity Center region could be run as many times as you require. You could refer to the execution input that the solution uses as part of the pipeline deployment for reference.

De-couple life cycle management of different SSO objects and other features

  • The solution enables de-coupling creation of permission sets , user groups and account assignment operations completely. They could be created in any sequence, thereby enabling enterprise teams to handle these objects lifecycles through different workflow process that align to their needs, and the solution would handle the target state appropriately
  • The solution enables usage of friendly names in managing permission set, account assignment life cycles and would handle the translation of friendly names into internal AWS IAM Identity Center GUID's automatically
  • The solution enables deployment in a distributed model i.e. orgmain, deployment and target account (or) in a single account model i.e. orgmain only. It's recommended that single account model of deployment be used only for demonstration purposes
  • The solution assumes that AWS IAM Identity Center is enabled in a different account other than orgmain account and has the required cross-account permissions setup to enable the functionalities. This future-proofs the solution to support the scenario when AWS IAM Identity Center service releases delegated admin support similar to other services such as GuardDuty

Schema details for account assignment and permission set operations

  • For account assignment operations with API interface
    • action should be exactly one of create, delete
    • linkData should match this format: scopetype%scopevalue%permissionsetname%principalname%principaltype%ssofile
  • For account assignment operations with S3 interface
    • file name should match this format: scopetype%scopevalue%permissionsetname%principalname%principaltype%ssofile
    • file contents are empty i.e. empty file
  • For both interface types,
    • scopetype should be exactly one of root, ou_id, account_tag, account
    • scopevalue sould match the keyword all if scopetype is set to root
    • scopevalue should match the organisational unit ID if scopetype is set to ou_id
    • scopevalue should match tagkey^tagvalue convention if scopetype is set to account_tag
    • scopevalue should have account number if scopetype is set to account
    • permissionsetname should match permission set name
    • principalname should match displayname if principal type is group , else it should match username if principal type is user
    • principaltype should be exactly one of GROUP, USER
  • For permission set operations with API interface
    • action should be exactly one of create, update, delete
  • For permission set operations with S3 interface
    • file name should match this format: permisssionsetname.json

Using API interface for your use cases

If you chose to use API interface for managing your permission sets and account assignments i.e. set LinksProvisioningMode or PermissionSetProvisioningMode to api, then read below for usage instructions:

  • Refer to postman collection sample under docs\samples\postman-collection for account assignment and permission set operation examples
  • More details on using API interface are documented here

Using S3 interface for your use cases

If you chose to use S3 interface for managing your permission sets and account assignments i.e. set LinksProvisioningMode or PermissionSetProvisioningMode to s3, then read below for usage instructions:

  • Refer to sample files under docs\samples\links_data for account assignment operations and docs\samples\permission_sets for permission set operations

  • After deploying the solution with S3 interface, navigate to target account and under env-aws-sso-extensions-for-enterprise-preSolutionArtefactsStack outputs , you will have the S3 locations for uploading your permission sets and account assignments

  • For account assignment operations, uploading a file to the S3 prefix path would map to creating an account assignment and deleting a file from the S3 prefix path would map to deleting an account assignment

  • For permission set operations, uploading a new file to the S3 prefix path would map to creating a permission set, uploading a new copy of the file would map to updating the permission set, and deleting the file would map to deleting the permission set

  • Ensure your deployment account has a cloudtrail. If not, the solution will not be able to provision permission sets when moving in and out of OUs as these events will not register with the event bus.

Security

See CONTRIBUTING for more information.

License

This library is licensed under the MIT-0 License. See the LICENSE file.

aws-iam-identity-center-extensions's People

Contributors

allquixotic avatar amazon-auto avatar debojitmegaco avatar dependabot[bot] avatar jjleigh avatar jmejco avatar leelalagudu avatar tamara-h avatar vpegg avatar zzamboni avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aws-iam-identity-center-extensions's Issues

Account provisioning does not work for tripple nested OUs

When you try to create an account provision using an OU that has tripple or more levels of nesting the provisioning does not work. No error no indication of failure. The messages are not enqueued but the links handler lambda is triggered.

Example structure:

  • OU.1
    • Sub-OU-a
      • Sub-OU- 123
        • account 1
        • account 2
        • account 3
      • Sub-OU- 456
        • account 4
        • account 5
        • account 6
    • Sub-OU-b
      • Sub-OU- 789
        • account 7
        • account 8
        • account 9
        • account 10

If an account assignment is created for OU.1 none of the accounts nested in the grandchildren OUs will be assigned to the permission set. No error will occur.

Refactor PR workflow

Refactor PR workflow to move away from the team maintained CICD stack to an org based stack (probe) - for sast build project. This would alleviate ops burden from the team and ensure that the sast checks are always up-to-date

remove: External dependencies where feasible

The solution currently uses one external dependency to calculate object based diff on the basis of Dynamo DB stream record. This is particularly useful to understand the exact delta that permission set operation has triggered. However, native AWS JS SDK v3 has now introduced support for marshaller and unmarshaller interfaces , giving the flexibility to do this computation directly without relying on third party libraries.
https://github.com/Nordstrom/dynamo-stream-diff

The purpose of this request is to refactor logic to move away from using this third party dependency

Documentation is missing instructions on using S3 as provisioning interface.

Per the title, there is no information on how to use files into the S3 bucket as the provisioning interface. I've been trying to work with the files provided, as well as what is already in the bucket from the SSO current state import, but it is not working out for me. Using one of the files from permissions_sets folder, I get errors, and guessing at a proper format is not getting me any closer to deployment.

{"Subject":"Error Processing Permission Set create/update via S3 Interface","eventDetail":{"eventVersion":"2.1","eventSource":"aws:s3","awsRegion":"us-west-2","eventTime":"2022-01-19T16:37:13.277Z","eventName":"ObjectCreated:Put","userIdentity":{"principalId":"_REDACTED_"},"requestParameters":{"sourceIPAddress":"_REDACTED_"},"responseElements":{_REDACTED_},"s3":{"s3SchemaVersion":"1.0","configurationId":"MjM2YmU4OWQtZDBlMC00NDI4LTgzZjEtYTFiM2QwNmU4M2Jk","bucket":{"name":"_REDACTED_","ownerIdentity":{"principalId":"_REDACTED_"},"arn":"_REDACTED_"},"object":{"key":"permission_sets/CloudOperators-ps-s3.json","size":1631,"eTag":"9826505bb7f8b0c45cc73d02d500e7c6","sequencer":"0061E83E3932B78E92"}}},"errorDetails":{"errors":[{"errorCode":"additionalProperties","message":"must NOT have additional properties"},{"errorCode":"required","message":"must have required property 'permissionSetName'"}]}}

Provide unit test coverage to lambda functions

  • Write unit tests for all lambda functions
  • Add test stage to pipeline validating the completeness and correctness of the lambda functions
  • Integrate the test stage as part of the PR workflow

Enable switching AWS SSO region

We have had multiple customers ask for this requirement from the solution:

  • For various reasons, customers choose to migrate AWS SSO from one region to another region and are looking for a solution that would help them reduce the migration time.

  • This user story should enable the following flow for customers willing to migrated AWS SSO from one region to another region:

  1. The customer would run a discover script that would discover all the permission sets and account assignments in their current AWS SSO region in a format that would be compatible with the next scripts
  2. The customer would then do the AWS SSO region switch to the new region manually (as there are no API's currently to enable this). The customer would then also set up their identity store and identities (users & groups) in the new region as well (this is again a manual operation currently as there are no API's available)
  3. The customer would then run a deploy script that would then create the permission sets and account assignments discovered in step 1 in the new region.
  4. This would complete the AWS SSO region migration process.

Migrating Fine-grained Per-account RBAC from AWS Directory Service

Originally "Problem 2" from #42

This is a feature request and business justification is supplied.

Assumptions:

Note: Not all of these assumptions must be true for a potential solution to have value.

  • The organization has many member accounts. The number is high enough that automation is desired.
  • The organization has many users. The number is high enough that automation is desired.
  • The organization currently uses AWS Directory Service to authenticate and authorize users.
    • Users are allowed to assume a role upon accessing the AWS Console based on the definitions in the Delegate console access section of AWS Directory Service (under Application Management).
    • The role the user assumes has an established Trust Relationship to assume role into various scoped roles within the desired member account.
    • Users log in using a directory portal on awsapps.com, which then prompts them for which delegated console access role they wish to assume.
  • For Least Privilege reasons, each user is only delegated roles for accounts they need. Example, if we have 50 accounts, a single user might be able to assume 1 to 5 roles depending on their individual need.
  • Most (but not all) of the IAM roles in the member accounts that get assumed, are different from each other... there isn't a standard cookie-cutter "persona" or set of personas that apply to all accounts.
  • The organization wishes to migrate from the existing Directory Service based login to AWS SSO, while maintaining the current Least Privilege RBAC, consisting of thousands of data points associating users with the roles they are allowed to assume.
  • The users do not have AD Groups already assigned to them that correspond to the IAM roles they have in Directory Services' delegated console access.

Problem:

  • In our Delegate console access list in Directory Services, there are thousands of data points (user -> IAM role mappings). Manually recreating all these data points as AD Groups + Permission Sets + Accounts would take weeks of man-hours of work, and would be error-prone.
  • We will have to create all the appropriate permission sets and groups in AWS SSO and AD (or, if not in AD, at least in AWS SSO!)
  • Ongoing maintenance question: where do we store this data in a way that it's versioned and auditable? Even if we had 0 users currently, this would be an issue.

Ad-Hoc Automation Solution:

Not yet implemented, but I am envisioning another script that reads all the roles, policies and access delegations from our current Directory Service (it will need cross account IAM access into each member account to read the policies underlying each role) and uses that as a data source to recreate an equivalent using Permission Sets and Groups in AWS SSO.

Update: I am concerned that this might not work. I can't find an API to access the Delegate console access list. See https://stackoverflow.com/questions/70903608/aws-directory-service-delegate-console-access-api-or-cli-command

What Could SSO Extensions Do:

Something similar to the ad-hoc, but with self-maintenance using CodePipeline, and more configurable / robust than what I'll probably build ...

Permission set schema doesn't handle NotAction and NotResource

When I upload this permission set to S3 as "permission_sets/Foo.json", I receive an email from SNS.

First, here's the permission set (and yes, the total character length is well below 10240 characters):

{
    "permissionSetName": "Foo",
    "sessionDurationInMinutes": 720,
    "managedPoliciesArnList": [
        "arn:aws:iam::aws:policy/AdministratorAccess",
        "arn:aws:iam::aws:policy/AWSSupportAccess"
    ],
    "inlinePolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Resource": "*",
                "Effect": "Deny",
                "NotAction": [
                    "s3:*",
                    "ec2:*",
                    "ec2-reports:*",
                    "iam:*", #About 50 more whitelisted services here
                ]
            },
            {
                "Condition": {
                    "StringNotLike": {
                        "aws:RequestedRegion": "us-east-1"
                    }
                },
                "Action": "*",
                "Resource": "*",
                "Effect": "Deny"
            },
            {
                "Action": [
                    "s3:PutAccountPublicAccessBlock",
                    "s3:PutBucketAcl"
                ],
                "Effect": "Deny",
                "NotResource": [
                    "arn:aws:s3:::bucket1",
                    "arn:aws:s3:::bucket2"
                ]
            }
        ]
    },
    "relayState": "https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1#",
    "tags": [
        {
            "Key": "versionid",
            "Value": "01"
        }
    ]
}

The errors:

[
    {
        "errorCode": "type",
        "message": "must be string"
    },
    {
        "errorCode": "required",
        "message": "must have required property 'Action'"
    },
    {
        "errorCode": "additionalProperties",
        "message": "must NOT have additional properties"
    },
    {
        "errorCode": "anyOf",
        "message": "must match a schema in anyOf"
    },
    {
        "errorCode": "type",
        "message": "must be array"
    },
    {
        "errorCode": "anyOf",
        "message": "must match a schema in anyOf"
    },
    {
        "errorCode": "required",
        "message": "must have required property 'Resource'"
    },
    {
        "errorCode": "additionalProperties",
        "message": "must NOT have additional properties"
    },
    {
        "errorCode": "anyOf",
        "message": "must match a schema in anyOf"
    }
]

When I manually submit the inline policy to the AWS SSO console, it works, so this is a limitation of SSO Extensions. Seems really restrictive not to permit NotAction, NotResource!

Permission sets failing to create with no SNS error

I wrote up an example of this failure in the PR notes at #89

This is now happening for multiple permission sets, and majorly impacting our production rollout / migration from Directory Service.

  • Far as I can tell, the JSON for the permission set is 100% compliant with the schema (and if I introduce an error that violates the schema, I get an email through SNS as expected). The inlinePolicyDocument is well under 10240 characters (only about 7k).
  • No email arrives and no permission set gets created.
  • I deleted the links data first before uploading the permission set.
  • When uploading the permission set (at a time when the permset does not exist "live" in AWS SSO, the permset does not have any links data applied to it, and the permset does not currently exist in S3) : env-psCuHandler CW log just shows a statusMessage of "Permission Set operation is being processed" and a "status" of "InProgress".

When the permission set .json already exists in S3 but the permission set does not exist in AWS SSO, I get the following from env-permissionSetTopicProcessor:
status: InProgress,
statusMessage: PermissionSet topic processor delete operation in progress
then,
status: Completed,
statusMessage: PermissionSet delete operation - no reference found, so not deleting again

Afterward, if I try to re-upload it, I get:

status: InProgress,
statusMessage: PermissionSet topic processor update operation in progress
then,
status: InProgress,
statusMessage: PermissionSet update operation - Calculating delta
then,
status: Completed,
statusMessage: PermissionSet update operation - no delta determined, completing update operation

How can there be no "delta" when the permission set does not exist in SSO?

Simplest permission set that will reproduce this problem:

{
  “permissionSetName”: “foo”, “sessionDurationInMinutes”: “720”, 
  “managedPoliciesArnList”: [“arn:aws:iam::aws:policy/AdministratorAccess”, “arn:aws:iam::aws:policy/AWSSupportAccess”],
  “inlinePolicyDocument”: {},
  “relayState”: “https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1#”,
  “tags”: [ { “Key”: “something”, “Value”: “someval” } ]
}

I feel like I'm stuck without a way to proceed, because permission sets just get silently ignored by SSO Extensions for reasons it won't tell me, and all I can figure is that it has some stale state somewhere inside of SSO Extensions that isn't in current sync with what is "live" in AWS SSO.

If this is the case, SSO Extensions needs to frequently and regularly sync its current picture of the live AWS SSO state with the actual state, to account for possible changes via the SCIM API and AWS API. This permission set may have been one that I deleted by hand, but SSO Extensions should not assume that any of its cache of the AWS SSO data is current and accurate.

Error emails upon adding users

Hi,

With S3 provisioning mode and a successfully deployed stack in single region/single account, with all initial setup CodePipelines successfully executed, I receive the following emailed error every time I add a user to AWS SSO. I get a similar error when adding a group. We are using Okta as External IdP with SCIM enabled. Can you tell what sort of issue this might be?

I have a good feeling that my links_data and permissions_data are valid, because when I uploaded my .ssofiles and .json to each respective folder in S3, pipelines ran without error. Then when I look in the AWS SSO console manually, the changes I expected (permission set creation, account/group/permission set assignment, etc.) all seemed to come through correctly.

I don't know why the solution needs to care about user add/delete at all, since none of my links_data refer to users. All of them only refer to .GROUP.ssofile, meaning that user CRUD should not affect anything in the SSO Extensions solution. I guess it still has to process the user add event to determine that, but then, the cause of the error is not apparent to me.

{
    "Subject": "Error Processing group trigger based link provisioning operation",
    "eventDetail": {
      "Records": [
        {
          "EventSource": "aws:sns",
          "EventVersion": "1.0",
          "EventSubscriptionArn": "arn:aws:sns:us-east-1:(redacted-acctid):env-aws-sso-extensions-for-enterprise-ssoEventsProcessorStack-envssoGroupEventsNotificationTopicredacted-identifier:redacted-guid",
          "Sns": {
            "Type": "Notification",
            "MessageId": "redacted-guid",
            "TopicArn": "arn:aws:sns:us-east-1:(redacted-acctid):env-aws-sso-extensions-for-enterprise-ssoEventsProcessorStack-envssoGroupEventsNotificationTopicredacted-identifier",
            "Subject": null,
            "Message": "{\"version\":\"0\",\"id\":\"redacted-guid\",\"detail-type\":\"AWS API Call via CloudTrail\",\"source\":\"aws.sso-directory\",\"account\":\"(redacted-acctid)\",\"time\":\"2022-01-28T13:48:23Z\",\"region\":\"us-east-1\",\"resources\":[],\"detail\":{\"eventVersion\":\"1.08\",\"userIdentity\":{\"type\":\"Unknown\",\"accountId\":\"(redacted-acctid)\",\"accessKeyId\":\"redacted-guid\"},\"eventTime\":\"2022-01-28T13:48:23Z\",\"eventSource\":\"sso-directory.amazonaws.com\",\"eventName\":\"CreateGroup\",\"awsRegion\":\"us-east-1\",\"sourceIPAddress\":\"redacted-ip\",\"userAgent\":\"python-requests/2.27.1\",\"errorCode\":\"InternalFailure\",\"errorMessage\":\"An unknown error occurred\",\"requestParameters\":{\"identityStoreId\":\"d-redacted-id-store-id\",\"displayName\":\"redacted-group-display-name\",\"groupAttributes\":{}},\"responseElements\":null,\"requestID\":\"redacted-guid\",\"eventID\":\"redacted-guid\",\"readOnly\":false,\"eventType\":\"AwsApiCall\",\"managementEvent\":true,\"recipientAccountId\":\"(redacted-acctid)\",\"eventCategory\":\"Management\",\"tlsDetails\":{\"clientProvidedHostHeader\":\"up.sso.us-east-1.amazonaws.com\"}}}",
            "Timestamp": "2022-01-28T13:48:44.916Z",
            "SignatureVersion": "1",
            "Signature": "redacted-b64-signature",
            "SigningCertUrl": "redacted-SNS-url"
          }
        }
      ]
    },
    "errorDetails": {}
  }

Add customer managed policy and permission boundaries

AWS SSO has added the ability to add customer managed policies and permission boundaries to a permission set in the console. This functionality needs to be supported in the the create and update permission set workflow.

Intermittent unhandled API exception with AWS SSO admin API

We've noticed a particular issue with AWS SSO admin API:

  • When we try and update managed policies list attached to a permission set i.e. run multiple async DetachManagedPolicyFromPermissionSet and AttachManagedPolicyToPermissionSet calls, the API sometimes responds with an unhandled exception. The exception class is undefined which is evidenced by the V3 JS SDK client failing to parse the response and throwing TypeError: Converting circular structure to JSON message. The solution currently has an exponential back-off based retry mechanism, however since this exception is not even understood by the SDK client, the retry isn't helping as well. This is therefore causing incorrect behaviour where an update of the managed policies array is not being processed completely.
  • We've already raised an internal ticket with the AWS SSO service team for this issue and are working with them to provide related logs so that the service team has all the details to understand the root cause.
  • #38 also indicated that the same kind of unhandled API exceptions are thrown by AWS SSO admin API even during an Identity store describe user API call.
  • Until the service team identifies the root cause and provides recommendations on how to handle this, we're blocked on this issue.

Does SSOEx hit AWSOrganizations API regularly?

Hi,

We are doing a proof of concept of AWS Firewall Manager in the same OrgMain account as our SSOEx solution (which is deployed in a single-region, single-account configuration).

We notice that AWS Firewall Manager sometimes faces errors with the AWS Organizations API such as:

Unable to enable sharing with AWS Organizations. 
Received TooManyRequestsException from AWSOrganizations with the following error message: AWS Organizations can't complete your request because another request is already in progress. Try again later.

In trying to root cause why we're being rate limited, we wondered if SSOEx might be hitting AWS Organizations often. Does any ongoing / scheduled code in SSOEx use the Organizations API?

How about if we do SCIM operations against AWS SSO? In that case, do the Lambda triggers resulting from that perform any Organizations API calls?

To be clear, this is a question, not a defect - trying to understand product behavior as part of a troubleshooting session.

Permisison set schema validation bug

Permission set create/update API schema and S3 schema do not validate the inline policy content. This bug allows creation of a permission set with an improper inline policy document attached.

AC:

  1. Update the schema definitions such that they would validate an inline policy document is properly formatted

Customizing env.yaml

Per the workshop, customizing the Environment requires updating both the file name of config/env.yaml, and the variable Environment in the file.

The workshop does not provide any instructions for how to change things when changing the App variable.

I tried changing both of these and had no end of errors, especially with the yarn commands, which seem to assume that the Environment and App are set to default.

Also the pipeline itself is not aware of changes to the Environment variable, and fails on something like No such file or directory: config/env.yaml. So in essence, these values must be hard coded to their original values, or the IaC and the yarn scripts fail. This seems to conflict with the intended purpose of having configurable variables for them.

Extend region switch feature to Organization/management account switch

I have customers who are requesting the ability to migrate their SSO setup to a new management account in a new AWS Organization. This is especially useful when a customer wants to stand up a new Organization with the intent of establishing AWS Control Tower with a clean management account. The customer who have spent considerable time to build custom permission sets, need a way to be able to carry over their current SSO setup the management account of the new Org, in the same or another region.

Investigate git submodules / other design patterns that support modular feature design

This issue is to investigate the feasibility of git submodules/similar mechanisms to breakdown the current mono repo into a more manageable modular repo.
At the moment, the solution supports the following features all under a single monorepo:

  • Composite permission sets & enterprise friendly account assignments
  • Region switch
  • Import current configuraiton
    The solution has the following features that are being developed/in pipeline:
  • Org main account switch
  • Privileged access management

Without a well defined modular repo structure, the solution would soon transform into a monolith increasing the risk of regression and ops burden.

AC:

  • Design and document a architecture decision record(ADR) for the modular system proposed
  • Refactor the solution as well as the self-mutating pipeline to fit into this system

OrgMain account not affected by root.all?

Hi,

In S3 provisioning mode, if I create a file in links_data like this:

root.all.Admin-ps.Admins.GROUP.ssofile

This causes all the member accounts to get the permission set Admin-ps for the Admins group.

However, the Org Main account (the master payer account) does not receive this change. In fact, I have never observed SSO Extensions touching the settings of the Org Main account in the AWS SSO console at all.

Is this intended? Can it be overridden if this is intended behavior? I realize it could be dangerous to affect SSO settings of the master payer account, but we have IAM and (if necessary) root account credentials for it, so we won't be able to lock ourselves out of our account using SSO Extensions. We can always recover from whatever settings we apply.

ThrottlingException

Receiving throttling exception in these 2 situations:

  • When account assignment is created with a permission set that has 'undefined' as the value for the relay state
  • When account assignment is created and the OU or tag has more than 40 accounts. The SQS queues the right number but after 40 the link handler is throttled and none of the unprocessed messages end up in the dead letter queue.

This was tried on an OU with 72 accounts but only 40 were provisioned.

Here is part of the error bellow:

Subject: Error Processing link provisioning operation

"eventSource":"aws:sqs","eventSourceARN":"arn:aws:sqs:us-east-<account_number>:env-linkManagerQueue.fifo","awsRegion":"us-east-1"}]},"errorDetails":{"name":"ThrottlingException","$fault":"client","$metadata":{"httpStatusCode":400,"requestId":"6cd844bc-a51b-414d-89f9-c9723df46bcb","attempts":2,"totalRetryDelay":175},"__type":"ThrottlingException","message":"There are too many requests processing. Please try again later."}}

featureRequest: Observability

Objective

Provide visibility into all transactions processed by the solution along with their respective statuses and any additional information that would help the end user to understand the status and/or reason for a transaction failure

The solution should provide the following changes/enhancements in order to enable this feature:

  • Provide a tracing mechanism that would use a unique ID i.e. traceId and log the details of the traceId along with the transaction state changes as it progresses #30
  • The end user should be able to use Cloudwatch log group insights to understand exactly what's happened with a particular traceId #30
  • The solution should be re-factored to enable the core provisioning flows for links and permission sets to be triggered off a FIFO based SQS queue and along with this, move the core dynamoDB table CRUD operations as side channel operations. #25
  • The solution should make the trace routines within the solution extensible enough to facilitate replacing the tracing persistence layer from cloudwatch log groups to a different system like Grafana in the future #30

Option to make APIs / S3 uploads "always update" the solution

Thinking about recent problems I've been having, I think the problems would be best resolved by enabling a mode in SSOEx where any API calls into the SSOEX API, or -- in S3 mode -- any bucket data changes -- cause the current state in the DynamoDB solution to be overwritten unconditionally.

For example, let's say we have the following state:

  • In SSO live: Permission set doesn't exist (say a user deleted it).
  • In Dynamo: Permission set exists because it was originally created via SSOEx (through S3) and SSOEx isn't aware that the live state includes the permset being deleted.
  • In S3: Permission set has been "re-uploaded", overwriting an identical copy of the file from before, with intent to restore the permset to live.

I would expect that SSO live would include the latest permset data from S3 after the S3 bucket PutObject occurs, even if the data in the permset is the same as what DynamoDB has.

More confusingly, even if I change the content of the permset, such as bumping a version tag, SSOEx still refuses to create the permset again in live, once it has been deleted.

As currently implemented, the solution is extremely fragile and cannot handle any changes made to SSO configuration outside of SSOEx.

I want to arrive at a "Latest Change Wins" model where the possible sources of change include S3 updates or manual management console updates (in any sequencing/order).

Analogy... If we think of the "live" SSO state as a mutable (editable) Wikipedia article, and there are 3 people editing the page, and they all click save... the latest person to hit save gets their changes published. This is the model I want.

Enable provisioning of permission set to orgMain / delegated admin account

  • There's been a recent change in the SSO admin API, wherein using specific IAM permisisons, you could now programmatically create/delete account assignments for org main/delegated admin account.
  • The solution currently excludes provisioning to org main/delegated admin account as the earlier version of SSO admin API did not allow this.
  • However, using the following permissions policy, provisioning lambda can now successfully assign/remove account assignment to org main / delegated admin account
{
    effect = "Allow"
    actions = [
      "iam:CreateRole",
      "iam:ListRolePolicies",
      "iam:AttachRolePolicy",
      "iam:PutRolePolicy"
    ]
    resources = [
      "arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO*",
    ]
  }

  statement {
    effect = "Allow"
    actions = [
      "iam:GetSAMLProvider",
      "iam:CreateSAMLProvider"
    ]
    resources = [
      "arn:aws:iam::*:saml-provider/AWSSSO*",
    ]
  }

AC:

  • The solution should now programmatically switch the permissions it uses to provision based on the target account it's provisioning the account assignment to
  • Update docs to remove this limitation

Permission set uses name for description field

The solution has a bug where in it uses permission set name for the description field of the object irrespective of what value is provided for description. This needs to be fixed to read whatever value description field is set as.

featureRequest: One-time migration of existing AWS SSO data

Enterprise customers who've already used AWS SSO would have existing data i.e. permission sets and account assignments that the solution would not be aware of. The solution should provide a capability to do:

  1. One-time import of existing data as part of the solution deployment
  2. Continuous synchronization to ensure any AWS SSO modifications done outside the solution scope will be handled automatically

Asynchronous flows - exception handling

The solution currently handles exception handling/error feedback using the following pattern:

  • Synchronous validations are performed when operations are being done by end user through S3/API interface.
  • For synchronous validations through API interface, the feedback is provided as part of response payload.
  • For synchronous validations through S3 interface, the feedback is logged to the cloudwatch log group.
  • For asynchronous validations that are executed as part of use case flows, the lambda functions have a catch all exceptions block and throws the exceptions to an error notification email.

Problem:

We've noticed different scenarios where the V3 JS SDK does not handle these exceptions correctly i.e. it does not process the exception resulting in an error notification that does not explain what the root cause of the exception is.

This is also observed in #38 , where the error notifications are not helpful towards understand where/why the exception occurred

Nightly runs to detect access artefacts drift

The solution should provide a config option during deployment where if the parameter is set to true, then the solution would:

  • run a nightly job that would detect if there's a difference between what the solution holds versus what the AWS SSO configuration reflects with regards to permission sets and account assignments.
  • If delta is detected, then the solution should do one of the two remediation actions depending on the option set by the user in configuration:
  1. Notify an email address chosen in the config for every drift detected
  2. Auto remediate to ensure that AWS SSO matches the solution repo with regards to permission sets and account assignments.

CloudWatch Logs Insights query name typos

The following CloudWatch Logs Insights query names have typos, Relateed should be changed to Related:

  • env-accountAssignmentAPIFlows-getRelateedRequestDetails
  • env-orgEventsTriggerFlows-getRelateedRequestDetails
  • env-permissionSetAPIFlows-getRelateedRequestDetails
  • env-permissionSetSyncTriggerFlows-getRelateedRequestDetails
  • env-ssoGroupTriggerFlows-getRelateedRequestDetails

Use clear, shorter, deterministic names for internal resources

I would like to suggest using clear, deterministic, shorter names for artifacts/resources that SSO Extensions creates.

Example: "env-aws-sso-extensions-f-envindependentutilityenv-10ygvcq...." (more stuff I'm not listing for security reasons) is the name of an S3 bucket in our stack where I have to put links_data and permission_sets.

To pull this string apart into its component pieces, we have:

env-: The name of the Environment in the config file (config/env.yaml) - OK, this is fine.
aws-sso-extensions-f-: Seems like the name of the project overall, just shortened a bit. It can be shortened more to ssox or ssoex.
envindependentutilityenv: This is really confusing for me, and this descriptor does not at all tell me "This is where you need to put the links_data and permission_sets".

10ygvcq...: This is a unique identifier because S3 buckets have to be unique globally. Fine.

I understand the reason it's so long is because CDK is auto generating this horrible name, but this is not user-friendly. It makes it difficult for us to understand what these objects are for.

Similarly with the CodePipelines and other aspects of the support stacks for SSO Extensions, they are too long and difficult to understand.

I would recommend shortening "AWS SSO Extensions for Enterprise" to "ssox" or "ssoex" to make room for more descriptive names. If the unique identifier strings are still required on the end of bucket names and pipelines, that's fine -- I'm mainly concerned with the prefix part that's confusing, and the envindependentutilityenv which is even more confusing.

Single account deployment fails in preSolutionArtefactsStack

When using the same AWS account and region for all accounts (target, orgmain, ssoservice and deployment), the CFT for preSolutionArtefactsStack fails creating env-orgEventsNotificationsTopicArn, because a resource with the same name already exists in orgEventsProcessorStack.

If the SSO extensions for enterprise cannot be used without at least some of the accounts or regions being distinct, this should be mentioned in the docs. Specifically, the docs should describe which of the four accounts (target, orgmain, ssoservice, and deployment) must be distinct for deployment to succeed. I am following the Workshop for deployment instructions.

Otherwise, if it should be possible to deploy to a single account and region, then this should be considered a bug.

Session duration as a parameter?

Hi, we'd like to be able to specify the maximum session duration of the LinkCallerRole and PermissionSetCallerRole in the parameters (env.yaml). The 1 hour default session expiration makes it difficult to even demo the APIs because of the effort it takes to setup Postman after getting a session token.

We'd probably keep it at a reasonably lower level once we have full automation and have implemented an automated consumer of the APIs, but for dev/test, the 1 hour session duration is very challenging to work with.

Despite IaC best practices, I've manually hacked the max session duration to 12 hours on the roles for now. I'm thinking cross-account-role.ts can be modified where the new Role constructor is invoked, to bring in a parameter from the configuration to optionally edit the session duration.

403 Forbidden error invoking postPermissionSetData

After following the workshop to configure this project and Postman (using the provided Postman project and an environment I created), I receive the error that the PermissionSetCallerRole does not have permission to call execute-api:Invoke on the API endpoint.

Inspecting the API Gateway endpoints in the Target account, I see the env-permissionSetApi and the env-linkApi have no resource policy configured (it's blank). I added a resource policy for the principal arn:aws:iam:(target account id):role/PermissionSetCallerRole to perform the action execute-api:Invoke on the resource arn:aws:execute-api:us-east-1:(target account id):(gateway domain name random string)/*/*/* and now the API call works.

If I try the link API, I get the same error with LinkCallerRole.

Questions:

  • Is the API supposed to be accessible with no Resource Policy set on the API Gateway endpoints?
  • Is the deployment of this project supposed to create a Resource Policy on the API Gateway endpoints?
  • If a Resource Policy is not used, what mechanism provides permissions for the API Gateway endpoints to be invoked?

Info:

  • I'm using one region everywhere (us-east-1) with two distinct accounts in total. Everything is in the Org Main account except for the "Target Account", which is a member of the organization. Target is a separate account mainly because the current release fails to deploy with a single account and region for the entire project (see my other GitHub issue).

I am not sure if this is a bug or a configuration issue on my end.

Docs to use consistent API names

AWS SSO Admin API. AWS SSO service has four categories of API’s , our solution only uses AWS SSO Admin API, AWS Identity Store API.

Referneces to AWS SSO API in the README.md and in the Workshop should be specific and consistent.

Space in group or user name should raise error

If you mistakenly add a file in the links_data folder that has a space in the group or user name the extension substitutes the space for a + symbol and tries to find a group with that name. If it does not exist it will not do anything and not indicate to the developer that there was an issue with the name. If it does exits it will lead the developer to believe that the assignment was done correctly when it was actually assigned to the wrong account.
For example: account%123456789012%Billing-ps%team-Accoun ntants%GROUP%ssofile will become account%123456789012%Billing-ps%team-Accoun+ntants%GROUP%ssofile. Instead of the replacement the solution should raise a validation error.

featureRequest: enable request tracking for use case flows

  • The solution should provide a facility to track use case flow requests
  • The solution should return back a UUID for synchronous requests made via API interface. However, the solution should enable the same behaviour for S3 interface driven requests as well
  • The solution should also provide visibility with the same UUID for all the child flows it triggers (for ex, when scope types are set to a value other than account , or when there's an asynchronous SSO entity operation like group being created)

3.0.3 upgrade fails

Hi,

An upgrade from 3.0.2 to 3.0.3 failed in the codepipeline envawsssoextensionsforenter

It failed in CDK Synth:

Error: UpgradeFromVersionLessThanV303 does not exist or is of not the correct data type.

Let me know if you need more context.

Add github as a source repo option

At this point of time, the solution enforces using AWS CodeCommit as the only source provider option for the solution. This request is to extend the solution to support GitHub as an additional source provider.

AC:

  1. Make source provider type part of the config interface
  2. Allow the pipeline to self-mutate and trigger based on git changes for all the supported source repo types
  3. Udpate docs and workshop content where appropriate to reflect all the supported source repo types

User/Group Management Without SCIM

Leela & AWS Team,

While attempting to roll out AWS SSO, my organization is encountering a number of AWS SSO challenges that exist outside the current feature-set boundary of SSO Extensions for Enterprise.

The original Problem 2 from this issue has been moved to #46

This issue is about User/Group Management Without SCIM.

Assumptions:

Note: Not all of these assumptions must be true for a potential solution to have value.

  • Using External IdP (e.g. Okta) with AWS SSO.
  • The external IdP does not support SCIM, or SCIM is gated behind a license that your organization does not have.
  • Entering users and groups by hand in the AWS Management Console is too much administrative overhead, due to the sheer number of users/groups.
  • Okta's backend is an on-prem Active Directory (i.e., AD is the system of record for user accounts).
  • AWS has a Managed AD instance that receives a one-way user/group sync from on-prem AD using Microsoft Identity Manager.

Problem:

  • Without another solution, we would have to either (1) purchase a license supporting SCIM on the External IdP side, or (2) manually duplicate all user CRUD operations (new user, delete user, update user, change user group assignments) both on the AD side, and on the AWS SSO side.
  • SSO is supposed to reduce maintenance burden, or at the very worst, keep it the same - not increase it!
  • Purchasing can be a challenging prospect for some organizations, even if the money is technically available. Okta may not even be the only IdP that requires additional purchases for SCIM.

Ad-Hoc Automation Solution:

  • Developing a Python script (soon to be a cron schedule-driven Lambda)
  • Script reads users from Managed AD, extracting email, name fields, username, and memberOf (the multi-valued list of every group the user is a member of) and stores the user data in an in-memory data structure.
  • Script issues REST calls to the AWS SSO SCIM endpoint, at a minimum creating non-existent users/groups, but (ideally) also updating out of date information.
    • Example: User legally changes their name; joins or leaves AD groups.
    • Most common calls are GET and POST to /scim/v2/Users, /scim/v2/Groups - sometimes with filters. Code is fairly formulaic and intuitive if one understands the AWS SSO SCIM limitations as documented.

Possible Variations:

  • Getting the user list from a different source, e.g. from Okta API natively, or some other IdP or database.
  • Perhaps some organizations might only want to implement a subset of the users in AD, not all. The import process should provide a hook to allow arbitrary code to run and accept/reject a potential user import, or even include whitelist/blacklist functionality.

What Could SSO Extensions Do:

  • Implement some kind of extensible variation of my ad-hoc automation solution idea.
  • Take care of the AWS SSO SCIM operations (CRUD) and only require the user to provide a "data source" (where are you getting the users from?). Could bundle a few common data sources.
  • Leverage your excellent CodePipeline infrastructure to auto maintain the new functionalities.
  • Optionally support configuring the solution at runtime in S3 or via API.

Are these possible future directions for SSO Extensions? (Would you accept pull requests if I ever figure out the internals of SSO-Ex enough to directly implement this using SSO-Ex's existing infrastructure? Would you consider / are you already working on this yourself?)

Thanks for reading...

featureRequest: Re-factor flow trigger logic

  • The solution currently uses DynamoDB stream events as the source for triggering the flow logic for both account assignment and permission set flows.
  • Using this mechanism limits ability to implement observability logic as the stream trigger creates a disconnect between any interface trigger and solution processing flow.
  • The recommendation is to replace the trigger point to be an SNS topic so that the trace ID would be persisted between the interface trigger and solution processing flow.

3.2.0 introduces resource update behaviour bugs for IAM roles

When a customer upgrades from 3.1.4 to 3.2.0, this introduces role replacement behaviour conflicts for the following roles and needs to be fixed:

  • env-accountAssignmentImportTopicArn-readerRole
  • env-smDescribe-ssoapi-roleArn-readerRole
  • env-permissionSetImportTopicArn-readerRole

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.