langchain-ai / langchain

🦜🔗 Build context-aware reasoning applications
https://python.langchain.com
MIT License
94.57k stars 15.3k forks source link

Issue: Amazon Bedrock can't load my credentials when called from a Lambda function #8800

Closed MustaphaU closed 8 months ago

MustaphaU commented 1 year ago

Issue you'd like to raise.

Bedrock can't seem to load my credentials when used within a Lambda function. My AWS credentials were set up in my local environment using environment variables. When I use the bedrock class directly, it is able to load my credentials and my code runs smoothly. Here is the RetrievalQA function that utilizes the bedrock class:

def qa(query):
    secrets = json.loads(get_secret())
    kendra_index_id = secrets['kendra_index_id']

    llm = Bedrock(model_id="amazon.titan-tg1-large", region_name='us-east-1')
    llm.model_kwargs = {"maxTokenCount": 4096}

    retriever = AmazonKendraRetriever(index_id=kendra_index_id)

    prompt_template = """
    {context}
    {question} If you are unable to find the relevant article, respond 'I can't generate the needed content based on the context provided.'
    """

    PROMPT = PromptTemplate(
    template=prompt_template, input_variables=["context", "question"])

    chain = RetrievalQA.from_chain_type(
    llm=llm,
    retriever=retriever,
    verbose=True,
    chain_type_kwargs={
    "prompt": PROMPT
    }
    )

    return chain(query)

The above code runs without issues when used directly. However, when used within a lambda function, it fails. The scripts file used to build my lambda function uses the bedrock class as written above, however, I run into the validation errors when I invoke the Lambda function. { "errorMessage": "1 validation error for Bedrock\n__root__\n Could not load credentials to authenticate with AWS client. Please check that credentials in the specified profile name are valid. (type=value_error)", "errorType": "ValidationError", "requestId": "b772f236-f582-4308-8af5-b5a418d4327f", "stackTrace": [ " File \"/var/task/main.py\", line 62, in handler\n response = qa(query)\n", " File \"/var/task/main.py\", line 32, in qa\n llm = Bedrock(model_id=\"amazon.titan-tg1-large\", region_name='us-east-1',) #client=BEDROCK_CLIENT)\n", " File \"/var/task/langchain/load/serializable.py\", line 74, in __init__\n super().__init__(**kwargs)\n", " File \"pydantic/main.py\", line 341, in pydantic.main.BaseModel.__init__\n raise validation_error\n" ]

As clearly indicated by the error message, bedrock couldn't load credentials.

Suggestion:

I have looked at the official documentation of the bedrock class but still do not understand why my code fails. Any help will be appreciated. @3coins @jasondotparse @hwchase17

dosubot[bot] commented 1 year ago

Answer generated by a 🤖

Answer

Hello @3coins, @jasondotparse, @hwchase17,

I understand that you're having trouble with the Bedrock class not being able to load your AWS credentials when called from a Lambda function. This issue is likely due to the difference in how AWS credentials are loaded in a local environment versus a Lambda function.

In your local environment, the Bedrock class is able to load your AWS credentials from the ~/.aws/credentials file or the ~/.aws/config file. However, when running in a Lambda function, these files are not available. Instead, AWS Lambda functions use IAM roles for permissions. The IAM role associated with your Lambda function needs to have the necessary permissions to access the Bedrock service.

To resolve this issue, you should ensure that the IAM role associated with your Lambda function has the necessary permissions to access the Bedrock service. If you're using the default AWS SDK for Python (boto3) client, it will automatically use the credentials associated with the IAM role of the Lambda function.

Here's the relevant part of the code that loads the credentials:

try:
    import boto3

    if values["credentials_profile_name"] is not None:
        session = boto3.Session(profile_name=values["credentials_profile_name"])
    else:
        # use default credentials
        session = boto3.Session()

    client_params = {}
    if values["region_name"]:
        client_params["region_name"] = values["region_name"]

    if values["endpoint_url"]:
        client_params["endpoint_url"] = values["endpoint_url"]

    values["client"] = session.client("bedrock", **client_params)

except ImportError:
    raise ModuleNotFoundError(
        "Could not import boto3 python package. "
        "Please install it with `pip install boto3`."
    )
except Exception as e:
    raise ValueError(
        "Could not load credentials to authenticate with AWS client. "
        "Please check that credentials in the specified "
        "profile name are valid."
    ) from e

In this code, if credentials_profile_name is not provided, it defaults to using the default credentials which, in the case of a Lambda function, would be the IAM role associated with the function.

There was a similar issue raised in the LangChain repository: AmazonKendraRetriever "Could not load credentials" error in latest release which was resolved by ensuring the IAM role associated with the Lambda function had the necessary permissions.

I hope this helps! Let me know if you have any other questions.

Sources


This response is meant to be useful, save you time, and share context. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

MustaphaU commented 1 year ago

Sorry I don't think it's an access issue since the IAM role associated with the Lambda function has full access to bedrock. Please see below: fn_resource bedrock_access_policy

dosubot[bot] commented 1 year ago

Answer generated by a 🤖

Answer

Hello,

The issue you're experiencing is due to how the Bedrock class is handling AWS credentials. When running in your local environment, the Bedrock class is able to access your AWS credentials from the ~/.aws/credentials file or ~/.aws/config files. However, in the AWS Lambda environment, these files are not available and the credentials are provided through environment variables.

The Bedrock class should be modified to use the default credentials when the credentials_profile_name is not provided. This will allow it to use the IAM role associated with the Lambda function. Here is the modified code:

    @root_validator()
    def validate_environment(cls, values: Dict) -> Dict:
        """Validate that AWS credentials to and python package exists in environment."""

        if values["client"] is not None:
            return values

        try:
            import boto3

            if values["credentials_profile_name"] is not None:
                session = boto3.Session(profile_name=values["credentials_profile_name"])
            else:
                # use default credentials
                session = boto3.Session()

            client_params = {}
            if values["region_name"]:
                client_params["region_name"] = values["region_name"]

            if values["endpoint_url"]:
                client_params["endpoint_url"] = values["endpoint_url"]

            values["client"] = session.client("bedrock", **client_params)

        except ImportError:
            raise ModuleNotFoundError(
                "Could not import boto3 python package. "
                "Please install it with `pip install boto3`."
            )
        except Exception as e:
            raise ValueError(
                "Could not load credentials to authenticate with AWS client. "
                "Please check that credentials in the specified "
                "profile name are valid."
            ) from e

        return values

In this code, if credentials_profile_name is not provided, it will use the default session which will automatically use the credentials provided by the IAM role associated with the Lambda function.

Please try this modification and let me know if it resolves your issue. If you have any further questions, feel free to ask.

Best, Dosu

Sources


This response is meant to be useful, save you time, and share context. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

jonathan260589 commented 1 year ago

Hi @MustaphaU,

In the end, did you find a solution? I would also be interested in running Bedrock from Lambda and I guess I am going to run in the same problem...

MustaphaU commented 1 year ago

Hi @jonathan260589 , I haven't found a solution till date.

gel001 commented 1 year ago

I haven't actually tried this in Lambda, but are you packaging the boto3 that comes with Bedrock with your Lambda function?

I ran around in circles for a bit running locally with the real error being this line:

        values["client"] = session.client("bedrock", **client_params)

...because the boto3 client that is the default pip install doesn't have support for the "bedrock" service. Once I made sure to use the bedrock-aware boto3 my auth issues went away.

hghandri commented 1 year ago

Hi,

I've faced a same issue and solved it via this link : https://github.com/aws-samples/amazon-bedrock-workshop/blob/77abc340c4548ae014f2b948bb607c7c3b8cf89c/00_Intro/bedrock_boto3_setup.ipynb

Bedrock service is not available in live is still in preview, you have to install manually a specific version of Boto3 to access this new feature.

I've tested and everything works fine.

Good Luck.

MustaphaU commented 1 year ago

I haven't actually tried this in Lambda, but are you packaging the boto3 that comes with Bedrock with your Lambda function?

I ran around in circles for a bit running locally with the real error being this line:

        values["client"] = session.client("bedrock", **client_params)

...because the boto3 client that is the default pip install doesn't have support for the "bedrock" service. Once I made sure to use the bedrock-aware boto3 my auth issues went away.

Yes, both new wheels (boto3 and botocore) are in my deployment package. The issue is not with bedrock being unsupported, otherwise the error would read "Unknown service: 'bedrock'. bedrock is an unknown service ........"

MustaphaU commented 1 year ago

Hi,

I've faced a same issue and solved it via this link : https://github.com/aws-samples/amazon-bedrock-workshop/blob/77abc340c4548ae014f2b948bb607c7c3b8cf89c/00_Intro/bedrock_boto3_setup.ipynb

Bedrock service is not available in live is still in preview, you have to install manually a specific version of Boto3 to access this new feature.

I've tested and everything works fine.

Good Luck.

Yes, both new wheels (boto3 and botocore) are in my deployment package. The issue is not with bedrock being unsupported, otherwise the error would read "Unknown service: 'bedrock'. bedrock is an unknown service ........"

hghandri commented 1 year ago

Fine if you already have done with package installation then you could write something like that :

from boto3
from langchain.llms import Bedrock

session = boto3.Session(region_name = 'us-west-2')
boto3_bedrock = session.client(service_name="bedrock")

# Langchain LLM
llm = Bedrock(client=boto3_bedrock, model_id="anthropic.claude-v2", region_name='us-west-2')

in this case you bypass your first issue and your needs credential are provided by lambda role and not from profile. I made it works on Lambda and it works for me

gel001 commented 1 year ago

That Exception block will swallow the unknown service exception and replace it with the generic credentials one:

except Exception as e: raise ValueError( "Could not load credentials to authenticate with AWS client. " "Please check that credentials in the specified " "profile name are valid." ) from e

As a test you could do the code like @hghandri suggests, that boto3_bedrock = session.client() call will tell you for sure if those Bedrock boto3 dependencies are really included or not.

MustaphaU commented 1 year ago

Fine if you already have done with package installation then you could write something like that :

from boto3
from langchain.llms import Bedrock

session = boto3.Session(region_name = 'us-west-2')
boto3_bedrock = session.client(service_name="bedrock")

# Langchain LLM
llm = Bedrock(client=boto3_bedrock, model_id="anthropic.claude-v2", region_name='us-west-2')

in this case you bypass your first issue and your needs credential are provided by lambda role and not from profile. I made it works on Lambda and it works for me

Unfortunately, I had tried this in one of my attempts to fix the issue but it didn't work as I was faced with another error. "Unknown service": ''bedrock. bedrock is an unknown service......, even though the boto wheels were installed in the deployment package. Here is a snapshot of the deployment package used to build the lambda function. image

MustaphaU commented 1 year ago

That Exception block will swallow the unknown service exception and replace it with the generic credentials one:

except Exception as e: raise ValueError( "Could not load credentials to authenticate with AWS client. " "Please check that credentials in the specified " "profile name are valid." ) from e

As a test you could do the code like @hghandri suggests, that boto3_bedrock = session.client() call will tell you for sure if those Bedrock boto3 dependencies are really included or not.

Unfortunately, I had tried this in one of my attempts to fix the issue but it didn't work as I was faced with another error. "Unknown service": ''bedrock. bedrock is an unknown service......, even though the boto wheels were installed in the deployment package. Here is a snapshot of the deployment package used to build the lambda function. image

And here is the query function in my main.py: image

Note: I do not encounter any of these issues when working in a SageMaker notebook or other environments.

gel001 commented 1 year ago

Not sure what to tell you, that error you seeing is almost assuredly because it doesn't have the right version of boto3.

MustaphaU commented 1 year ago

Not sure what to tell you, that error you seeing is almost assuredly because it doesn't have the right version of boto3.

Hence, my confusion. Perhaps lambda overrode the installed (custom) boto wheels with the default? Not sure.

hghandri commented 1 year ago

Hi @MustaphaU, Here it's clearly an issue with version of Boto3 and botocore. Did you install all specific dependencies like in documentation ?

Here the code :


#!/bin/sh

set -e

echo "(Re)-creating directory"
rm -rf ./dependencies
mkdir ./dependencies
cd ./dependencies
echo "Downloading dependencies"
curl -sS https://d2eo22ngex1n9g.cloudfront.net/Documentation/SDK/bedrock-python-sdk.zip > sdk.zip
echo "Unpacking dependencies"
# (SageMaker Studio system terminals don't have `unzip` utility installed)
if command -v unzip &> /dev/null
then
    unzip sdk.zip && rm sdk.zip && echo "Done"
else
    echo "'unzip' command not found: Trying to unzip via Python"
    python -m zipfile -e sdk.zip . && rm sdk.zip && echo "Done"
fi

Did you use docker image with Lambda ? Because all the library you need are too heavy to deployed simply in standard lambda package. Max allowed package size is 50MB. On my side I have attached an EFS to my Lambda where everything installed on it.

MustaphaU commented 1 year ago

@hghandri No, I didn't use a docker image. My package size is 48 MB but I had increased the memory allocated to the function to more than twice the package size. Please see below. image

image

LogeshwaranV commented 1 year ago

I haven't actually tried this in Lambda, but are you packaging the boto3 that comes with Bedrock with your Lambda function? I ran around in circles for a bit running locally with the real error being this line:

        values["client"] = session.client("bedrock", **client_params)

...because the boto3 client that is the default pip install doesn't have support for the "bedrock" service. Once I made sure to use the bedrock-aware boto3 my auth issues went away.

Yes, both new wheels (boto3 and botocore) are in my deployment package. The issue is not with bedrock being unsupported, otherwise the error would read "Unknown service: 'bedrock'. bedrock is an unknown service ........"

How did you overcome the unknown service error? I was trying to access the bedrock from boto3 from wheel file. I was able to run in my local but getting the unknown service error in the lambda container image. can you provide any steps I could I follow to overcome this issue?

MustaphaU commented 1 year ago

I haven't actually tried this in Lambda, but are you packaging the boto3 that comes with Bedrock with your Lambda function? I ran around in circles for a bit running locally with the real error being this line:

        values["client"] = session.client("bedrock", **client_params)

...because the boto3 client that is the default pip install doesn't have support for the "bedrock" service. Once I made sure to use the bedrock-aware boto3 my auth issues went away.

Yes, both new wheels (boto3 and botocore) are in my deployment package. The issue is not with bedrock being unsupported, otherwise the error would read "Unknown service: 'bedrock'. bedrock is an unknown service ........"

How did you overcome the unknown service error? I was trying to access the bedrock from boto3 from wheel file. I was able to run in my local but getting the unknown service error in the lambda container image. can you provide any steps I could I follow to overcome this issue?

Ensure you're using the boto3 and botocore wheels that support Bedrock. Refer to page 21 of the Amazon Bedrock User Guide . The required files are boto3-1.28.21-py3-none-any.whl and botocore-1.31.21-py3-none-any.whl available in the bedrock python sdk. Note that these wheels aren't on the official PIP repository, so you'll need to download and install them manually.

rodbutters commented 1 year ago

I still am having this issue with the production release of boto3. Gave my test lambda admin credentials. Is anyone having success with this?

acastro2 commented 1 year ago

I'm facing the same problem, locally with my credentials in the ~/.aws/credentials it works just fine, but in the Lambda it fails with:

  "errorMessage": "1 validation error for Bedrock\n__root__\n  Could not load credentials to authenticate with AWS client. Please check that credentials in the specified profile name are valid. (type=value_error)",

I don't think the upgrades above about boto3 make sense anymore since it is already in version 1.28.63 and clearly already supports bedrock.

UPDATE

Nevermind this, ended up finding out that the docker environment wasn't getting the latest version for the image that I was publishing. Once it got the latest, it works.

dosubot[bot] commented 9 months ago

Hi, @MustaphaU,

I'm helping the LangChain team manage their backlog and am marking this issue as stale. From what I understand, you encountered a problem with the Bedrock class not being able to load AWS credentials when used within a Lambda function, despite working fine when used directly. It seems that I suggested modifying the Bedrock class to use default credentials when the credentials_profile_name is not provided, allowing it to use the IAM role associated with the Lambda function. Other users also shared their experiences and suggestions, such as ensuring the correct version of boto3 and botocore are used and checking for the latest version of the docker environment.

Could you please confirm if this issue is still relevant to the latest version of the LangChain repository? If it is, please let the LangChain team know by commenting on the issue. Otherwise, feel free to close the issue yourself, or the issue will be automatically closed in 7 days. Thank you!