Repository: bentoml/BentoML

Issue:
Yatai does not handle the STS assumed role in operator.get_arn_role_from_current_aws_user()
**Describe the bug**
Yatai causes the error:
```
Error: sagemaker deploy failed: INTERNAL:Not supported role type assumed-role; sts arn is arn:aws:sts::103365315157:assumed-role/<rolename>/<username>
```

because [bentoml/yatai/deployment/sagemaker/operator.py](https://github.com/bentoml/BentoML/blob/master/bentoml/yatai/deployment/sagemaker/operator.py) does not handle assumed role by checking type_role[0] is either "user", "root", or "role".

```
def get_arn_role_from_current_aws_user():
    sts_client = boto3.client("sts")
    identity = sts_client.get_caller_identity()
    sts_arn = identity["Arn"]
    sts_arn_list = sts_arn.split(":")
    type_role = sts_arn_list[-1].split("/")
    iam_client = boto3.client("iam")
    if type_role[0] in ("user", "root"):
        role_list = iam_client.list_roles()
        arn = None
        for role in role_list["Roles"]:
            policy_document = role["AssumeRolePolicyDocument"]
            statement = policy_document["Statement"][0]
            if (
                statement["Effect"] == "Allow"
                and statement["Principal"].get("Service", None)
                == "sagemaker.amazonaws.com"
            ):
                arn = role["Arn"]
        if arn is None:
            raise YataiDeploymentException(
                "Can't find proper Arn role for Sagemaker, please create one and try "
                "again"
            )
        return arn
    elif type_role[0] == "role":
        role_response = iam_client.get_role(RoleName=type_role[1])
        return role_response["Role"]["Arn"]
 
    raise YataiDeploymentException(
        "Not supported role type {}; sts arn is {}".format(type_role[0], sts_arn)    # <-----
    )
```

However, as in [Boto3 STS get_caller_identity] (https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts.html#STS.Client.get_caller_identity), type_role[0] can be "assumed-role". Which is common in AWS when a user need to switch roles depending on the environment.

```
response = client.get_caller_identity(
)
print(response)
-----
Expected Output: {
    'Account': '123456789012',
    'Arn': 'arn:aws:sts::123456789012:assumed-role/my-role-name/my-role-session-name',    <----- "assumed-role"
    'UserId': 'AKIAI44QH8DHBEXAMPLE:my-role-session-name',
    'ResponseMetadata': {
        '...': '...',
    },
}
```




**To Reproduce**
Steps to reproduce the behavior:
1. With AWS CLI, assume role (https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role.html)
2. Run Sagemaker deployment.
```
$ bentoml sagemaker deploy my-first-sagemaker-deployment -b IrisClassifier:20200713155751_57AC77 --api-name predict
```
3. See error

**Expected behavior**
Assumed role situation is handled and causes no error at deployment.

**Screenshots/Logs**
If applicable, add screenshots, logs or error outputs to help explain your problem.
```
$ bentoml sagemaker deploy my-first-sagemaker-deployment -b IrisClassifier:20200713155751_57AC77 --api-name predict
...
==> WARNING: A newer version of conda exists. <==
  current version: 4.8.2
  latest version: 4.8.3

Please update conda by running

    $ conda update -n base -c defaults conda



[2020-07-14 10:47:28,586] INFO - #
# To activate this environment, use
#
#     $ conda activate base
#
# To deactivate an active environment, use
#
#     $ conda deactivate


|[2020-07-14 10:47:28,921] INFO - + pip install -r ./requirements.txt

/[2020-07-14 10:47:29,645] INFO - Collecting scikit-learn

|[2020-07-14 10:47:29,694] INFO -   Downloading scikit_learn-0.23.1-cp37-cp37m-manylinux1_x86_64.whl (6.8 MB)

\[2020-07-14 10:47:31,479] INFO - Collecting pandas

[2020-07-14 10:47:31,494] INFO -   Downloading pandas-1.0.5-cp37-cp37m-manylinux1_x86_64.whl (10.1 MB)

/[2020-07-14 10:47:33,745] INFO - Requirement already satisfied: bentoml==0.8.3 in /opt/conda/lib/python3.7/site-packages (from -r ./requirements.txt (line 3)) (0.8.3)

\[2020-07-14 10:47:33,969] INFO - Collecting threadpoolctl>=2.0.0

[2020-07-14 10:47:33,981] INFO -   Downloading threadpoolctl-2.1.0-py3-none-any.whl (12 kB)

|[2020-07-14 10:47:34,294] INFO - Collecting scipy>=0.19.1

[2020-07-14 10:47:34,308] INFO -   Downloading scipy-1.5.1-cp37-cp37m-manylinux1_x86_64.whl (25.9 MB)

|[2020-07-14 10:47:40,018] INFO - Collecting joblib>=0.11

[2020-07-14 10:47:40,031] INFO -   Downloading joblib-0.16.0-py3-none-any.whl (300 kB)

\[2020-07-14 10:47:40,134] INFO - Requirement already satisfied: numpy>=1.13.3 in /opt/conda/lib/python3.7/site-packages (from scikit-learn->-r ./requirements.txt (line 1)) (1.19.0)

[2020-07-14 10:47:40,136] INFO - Requirement already satisfied: python-dateutil>=2.6.1 in /opt/conda/lib/python3.7/site-packages (from pandas->-r ./requirements.txt (line 2)) (2.8.0)

/[2020-07-14 10:47:40,325] INFO - Collecting pytz>=2017.2

[2020-07-14 10:47:40,339] INFO -   Downloading pytz-2020.1-py2.py3-none-any.whl (510 kB)

\[2020-07-14 10:47:40,544] INFO - Requirement already satisfied: gunicorn in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (20.0.4)

[2020-07-14 10:47:40,551] INFO - Requirement already satisfied: prometheus-client in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.8.0)

[2020-07-14 10:47:40,555] INFO - Requirement already satisfied: psutil in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (5.7.0)

[2020-07-14 10:47:40,559] INFO - Requirement already satisfied: alembic in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.4.2)

[2020-07-14 10:47:40,564] INFO - Requirement already satisfied: ruamel.yaml>=0.15.0 in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.16.10)

[2020-07-14 10:47:40,575] INFO - Requirement already satisfied: tabulate in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.8.7)

[2020-07-14 10:47:40,579] INFO - Requirement already satisfied: aiohttp in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (3.6.2)

[2020-07-14 10:47:40,592] INFO - Requirement already satisfied: certifi in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (2020.6.20)

[2020-07-14 10:47:40,594] INFO - Requirement already satisfied: python-json-logger in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.1.11)

[2020-07-14 10:47:40,595] INFO - Requirement already satisfied: requests in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (2.22.0)

[2020-07-14 10:47:40,611] INFO - Requirement already satisfied: sqlalchemy-utils in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.36.7)

-[2020-07-14 10:47:40,674] INFO - Requirement already satisfied: sqlalchemy>=1.3.0 in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.3.18)

[2020-07-14 10:47:40,688] INFO - Requirement already satisfied: grpcio<=1.27.2 in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.27.2)

[2020-07-14 10:47:40,692] INFO - Requirement already satisfied: click>=7.0 in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (7.1.2)

[2020-07-14 10:47:40,693] INFO - Requirement already satisfied: py-zipkin in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.20.0)

[2020-07-14 10:47:40,698] INFO - Requirement already satisfied: configparser in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (5.0.0)

[2020-07-14 10:47:40,707] INFO - Requirement already satisfied: flask in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.1.2)

[2020-07-14 10:47:40,724] INFO - Requirement already satisfied: packaging in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (20.4)

[2020-07-14 10:47:40,728] INFO - Requirement already satisfied: humanfriendly in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (8.2)

[2020-07-14 10:47:40,733] INFO - Requirement already satisfied: docker in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (4.2.2)

/[2020-07-14 10:47:40,747] INFO - Requirement already satisfied: boto3 in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.14.17)

[2020-07-14 10:47:40,751] INFO - Requirement already satisfied: cerberus in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.3.2)

[2020-07-14 10:47:40,754] INFO - Requirement already satisfied: protobuf>=3.6.0 in /opt/conda/lib/python3.7/site-packages (from bentoml==0.8.3->-r ./requirements.txt (line 3)) (3.12.2)

[2020-07-14 10:47:40,757] INFO - Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.7/site-packages (from python-dateutil>=2.6.1->pandas->-r ./requirements.txt (line 2)) (1.14.0)

[2020-07-14 10:47:40,759] INFO - Requirement already satisfied: setuptools>=3.0 in /opt/conda/lib/python3.7/site-packages (from gunicorn->bentoml==0.8.3->-r ./requirements.txt (line 3)) (45.2.0.post20200210)

[2020-07-14 10:47:40,770] INFO - Requirement already satisfied: python-editor>=0.3 in /opt/conda/lib/python3.7/site-packages (from alembic->bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.0.4)

[2020-07-14 10:47:40,771] INFO - Requirement already satisfied: Mako in /opt/conda/lib/python3.7/site-packages (from alembic->bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.1.3)

[2020-07-14 10:47:40,777] INFO - Requirement already satisfied: ruamel.yaml.clib>=0.1.2; platform_python_implementation == "CPython" and python_version < "3.9" in /opt/conda/lib/python3.7/site-packages (from ruamel.yaml>=0.15.0->bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.2.0)

[2020-07-14 10:47:40,779] INFO - Requirement already satisfied: chardet<4.0,>=2.0 in /opt/conda/lib/python3.7/site-packages (from aiohttp->bentoml==0.8.3->-r ./requirements.txt (line 3)) (3.0.4)

[2020-07-14 10:47:40,781] INFO - Requirement already satisfied: multidict<5.0,>=4.5 in /opt/conda/lib/python3.7/site-packages (from aiohttp->bentoml==0.8.3->-r ./requirements.txt (line 3)) (4.7.6)

[2020-07-14 10:47:40,784] INFO - Requirement already satisfied: attrs>=17.3.0 in /opt/conda/lib/python3.7/site-packages (from aiohttp->bentoml==0.8.3->-r ./requirements.txt (line 3)) (19.3.0)

[2020-07-14 10:47:40,827] INFO - Requirement already satisfied: async-timeout<4.0,>=3.0 in /opt/conda/lib/python3.7/site-packages (from aiohttp->bentoml==0.8.3->-r ./requirements.txt (line 3)) (3.0.1)

[2020-07-14 10:47:40,829] INFO - Requirement already satisfied: yarl<2.0,>=1.0 in /opt/conda/lib/python3.7/site-packages (from aiohttp->bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.4.2)

[2020-07-14 10:47:40,836] INFO - Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /opt/conda/lib/python3.7/site-packages (from requests->bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.25.8)

|[2020-07-14 10:47:40,850] INFO - Requirement already satisfied: idna<2.9,>=2.5 in /opt/conda/lib/python3.7/site-packages (from requests->bentoml==0.8.3->-r ./requirements.txt (line 3)) (2.8)

[2020-07-14 10:47:40,853] INFO - Requirement already satisfied: thriftpy2>=0.4.0 in /opt/conda/lib/python3.7/site-packages (from py-zipkin->bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.4.11)

[2020-07-14 10:47:40,866] INFO - Requirement already satisfied: Werkzeug>=0.15 in /opt/conda/lib/python3.7/site-packages (from flask->bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.0.1)

[2020-07-14 10:47:40,878] INFO - Requirement already satisfied: itsdangerous>=0.24 in /opt/conda/lib/python3.7/site-packages (from flask->bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.1.0)

[2020-07-14 10:47:40,880] INFO - Requirement already satisfied: Jinja2>=2.10.1 in /opt/conda/lib/python3.7/site-packages (from flask->bentoml==0.8.3->-r ./requirements.txt (line 3)) (2.11.2)

[2020-07-14 10:47:40,885] INFO - Requirement already satisfied: pyparsing>=2.0.2 in /opt/conda/lib/python3.7/site-packages (from packaging->bentoml==0.8.3->-r ./requirements.txt (line 3)) (2.4.7)

[2020-07-14 10:47:40,887] INFO - Requirement already satisfied: websocket-client>=0.32.0 in /opt/conda/lib/python3.7/site-packages (from docker->bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.57.0)

[2020-07-14 10:47:40,891] INFO - Requirement already satisfied: jmespath<1.0.0,>=0.7.1 in /opt/conda/lib/python3.7/site-packages (from boto3->bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.10.0)

[2020-07-14 10:47:40,893] INFO - Requirement already satisfied: botocore<1.18.0,>=1.17.17 in /opt/conda/lib/python3.7/site-packages (from boto3->bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.17.17)

[2020-07-14 10:47:40,903] INFO - Requirement already satisfied: s3transfer<0.4.0,>=0.3.0 in /opt/conda/lib/python3.7/site-packages (from boto3->bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.3.3)

[2020-07-14 10:47:40,907] INFO - Requirement already satisfied: MarkupSafe>=0.9.2 in /opt/conda/lib/python3.7/site-packages (from Mako->alembic->bentoml==0.8.3->-r ./requirements.txt (line 3)) (1.1.1)

[2020-07-14 10:47:40,910] INFO - Requirement already satisfied: ply<4.0,>=3.4 in /opt/conda/lib/python3.7/site-packages (from thriftpy2>=0.4.0->py-zipkin->bentoml==0.8.3->-r ./requirements.txt (line 3)) (3.11)

[2020-07-14 10:47:40,912] INFO - Requirement already satisfied: docutils<0.16,>=0.10 in /opt/conda/lib/python3.7/site-packages (from botocore<1.18.0,>=1.17.17->boto3->bentoml==0.8.3->-r ./requirements.txt (line 3)) (0.15.2)

\[2020-07-14 10:47:41,027] INFO - Installing collected packages: threadpoolctl, scipy, joblib, scikit-learn, pytz, pandas

-[2020-07-14 10:47:49,756] INFO - Successfully installed joblib-0.16.0 pandas-1.0.5 pytz-2020.1 scikit-learn-0.23.1 scipy-1.5.1 threadpoolctl-2.1.0

|[2020-07-14 10:47:49,994] INFO - + for filename in ./bundled_pip_dependencies/*.tar.gz
+ '[' -e './bundled_pip_dependencies/*.tar.gz' ']'
+ continue

|[2020-07-14 10:47:53,748] INFO -  ---> 895e4a390376

[2020-07-14 10:47:53,749] INFO - Step 9/9 : ENV PATH="/bento:$PATH"
[2020-07-14 10:47:53,749] INFO - 

\[2020-07-14 10:47:53,797] INFO -  ---> Running in 2c5c72de1601

-[2020-07-14 10:47:53,890] INFO -  ---> 05b6fd2ed048

[2020-07-14 10:47:53,892] INFO - Successfully built 05b6fd2ed048

[2020-07-14 10:47:53,898] INFO - Successfully tagged 103365315157.dkr.ecr.ap-southeast-2.amazonaws.com/irisclassifier-sagemaker:20200713155751_57AC77

Error: sagemaker deploy failed: INTERNAL:Not supported role type assumed-role; sts arn is arn:aws:sts::103365315157:assumed-role/<rolename>/<username>
```


To give us more information for diagnosing the issue, make sure to enable debug logging:

Add the following lines to your Python code before invoking BentoML:
```python
import bentoml
import logging
bentoml.config().set('core', 'debug', 'true')
bentoml.configure_logging(logging.DEBUG)
```

And use the `--verbose` option when running `bentoml` CLI command, e.g.:
```bash
bentoml get IrisClassifier --verbose
```

**Environment:**
 - OS: [e.g. MacOS 10.15.5]
 - Python/BentoML Version [e.g. Python 3.7.6, BentoML-0.8.3]



Discussion:
Put a quick change.
```
    # elif type_role[0] == "role":
    elif type_role[0] in ["role", "assumed-role"]:
        role_response = iam_client.get_role(RoleName=type_role[1])
        return role_response["Role"]["Arn"]

    raise YataiDeploymentException(
        "Not supported role type {}; sts arn is {}".format(type_role[0], sts_arn)
    )
```

But got an error. Please advise what this code is suppose to achieve.
```
Error: sagemaker deploy failed: INTERNAL:Failed to create sagemaker model; AWS ClientError - operation: CreateModel, code: ValidationException, message: The execution role ARN "arn:aws:iam::103365315157:role/<rolename>" is invalid. Please ensure that the role exists and that its trust relationship policy allows the action "sts:AssumeRole" for the service principal "sagemaker.amazonaws.com".
```
@oonisim Sorry for the late response; I took time to catch up with AWS `assumed-role` since I am not familiar with it.

The error you are encountering `The execution role ARN "arn:aws:iam::103365315157:role/<>rolename>" ... "sts:AssumeRole" for the service principal "sagemaker.amazonaws.com"` is caused you didn't enable Sagemaker as one of your trusted relationships. 

Sagemaker model needs to have permission to model artifacts and docker image for deployment on ML compute instances or for batch transform jobs, by assuming the role from `ExecutionRoleArn`.   Since BentoML will get the current arn role from the current user.  You would have to include Sagemaker as part of your trusted relationships in your role's policy document.

This is an example of trusted relationships I used to test it out.
```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "ec2.amazonaws.com",
          "sagemaker.amazonaws.com"
        ],
        "AWS": "arn:aws:iam::ACCOUNT_ID:user/USER_NAME"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

I will create a PR that includes the `assumed-role` as part of the accept ARN.  Thank you for discovering this!

Resolving patch:
diff --git a/bentoml/yatai/deployment/sagemaker/operator.py b/bentoml/yatai/deployment/sagemaker/operator.py
--- a/bentoml/yatai/deployment/sagemaker/operator.py
+++ b/bentoml/yatai/deployment/sagemaker/operator.py
@@ -97,7 +97,7 @@ def get_arn_role_from_current_aws_user():
                 "again"
             )
         return arn
-    elif type_role[0] == "role":
+    elif type_role[0] in ["role", "assumed-role"]:
         role_response = iam_client.get_role(RoleName=type_role[1])
         return role_response["Role"]["Arn"]
 


Test patch: