Hello! I'm excited to get the Automation API up an...
# automation-api
c
Hello! I'm excited to get the Automation API up and running for my team---working on transitioning from Terraform to Pulumi right now. I just joined the Slack workspace, so please let me know if this is the wrong place to post this. I was able to preview/deploy/destroy a stack locally completely using the automation API, then when I went to run it in CI I needed to start using assumeRole (AWS) and ran into errors trying to get that config set up. One of them was "no default region set". So I'm back locally and trying to add in those parameters, but getting a weird error. I set the region in the stack config (when I just did the region it complained about
error configuring Terraform AWS Provider: AWS account ID not previously found and failed retrieving via all available methods. See <https://www.terraform.io/docs/providers/aws/index.html#skip_requesting_account_id> for workaround
, so I added the
skipRequestingAccountId
param)
Copy code
stack_config: Dict[str, Any] = {
        "aws:region": ConfigValue(
            "us-east-1"
        )  
    }

    stack_config["aws:skipRequestingAccountId"] = ConfigValue(True)
Then I create the stack, which seems to work fine.
Copy code
project_settings = ProjectSettings(
        name=project_name, runtime=project_runtime_info, backend=project_backend
    )
    stack_settings = StackSettings(
        secrets_provider=secrets_provider,
        encrypted_key=encrypted_key,
        config=stack_config,
    )
    workspace_options = LocalWorkspaceOptions(
        secrets_provider=secrets_provider,  # Eli (2/11/22): since secrets_provider is already given in the ProjectSettings, I don't know if it's needed in both places or if just one spot would be better. Unclear at the moment
        project_settings=project_settings,
        stack_settings={stack_name: stack_settings},
    )
    print(f"Stack Config before initialization: {stack_config}")  # allow-print
    stack = create_or_select_stack(
        stack_name,
        project_name=project_name,
        program=pulumi_program,
        opts=workspace_options,
    )
But then when I go to run
preview
I get an error that seems to potentially indicate that this config is creating a new provider that isn't being passed into my inline program (maybe)
Copy code
+ pulumi:pulumi:Stack: (create)
    [urn=urn:pulumi:eli-test::my_project::pulumi:pulumi:Stack::my_project-eli-test]
Resources:
    + 1 to create
 stderr: error: could not validate provider configuration: 1 error occurred:
        * Attribute must be a single value, not a map
My inline program is just a simple creation of a bucket as I work to get the automation API framework up and running
Copy code
def pulumi_program() -> None:
    s3.Bucket("bucket")
Am I somehow not telling my inline program to use the provider config created by my stack? or am I just going about this the wrong way to configure the provider? I don't have any special custom provider configuration settings I need right now, I just have a role ARN that I need to assume in CI that has the permissions to deploy changes)
imports here:
Copy code
from pulumi.automation import ConfigValue
from pulumi.automation import create_or_select_stack
from pulumi.automation import LocalWorkspaceOptions
from pulumi.automation import ProjectBackend
from pulumi.automation import ProjectRuntimeInfo
from pulumi.automation import ProjectSettings
from pulumi.automation import StackSettings
from pulumi.automation._stack import BaseResult
from pulumi_aws import s3
when I take out any
aws
namespace config settings, everything works fine when I run locally, and it appears to call the default provider
Copy code
Previewing update (eli-test):
+ pulumi:pulumi:Stack: (create)
    [urn=urn:pulumi:eli-test::my_project::pulumi:pulumi:Stack::my_project-eli-test]
    + aws:s3/bucket:Bucket: (create)
        [urn=urn:pulumi:eli-test::my_project::aws:s3/bucket:Bucket::bucket]
        [provider=urn:pulumi:eli-test::my_project::pulumi:providers:aws::default_4_37_2::04da6b54-80e4-46f7-96ec-b56ff0331ba9]
        acl         : "private"
        bucket      : "bucket-a25f88e"
        forceDestroy: false
Resources:
    + 2 to create
But in CI I need to be able to assume a role, so I was trying to use
Copy code
stack_config["aws:assumeRole"] = {
            "roleArn": ConfigValue(role_arn),
            "sessionName": ConfigValue(f"deploy {fully_qualified_stack_name}"),
        }
I'm using KMS as the secrets_provider if that makes any different
secrets_provider = f"awskms://{kms_key_id}"
pip freeze
results in my venv:
Copy code
Arpeggio==1.10.2
astroid==2.8.2
attrs==21.2.0
aws-lambda-typing==2.0.2
backports.entry-points-selectable==1.1.0
boto3==1.18.60
boto3-stubs==1.18.60
botocore==1.21.60
botocore-stubs==1.21.60
certifi==2021.10.8
cfgv==3.3.1
charset-normalizer==2.0.7
click==8.0.3
dill==0.3.4
distlib==0.3.3
filelock==3.3.0
grpcio==1.43.0
identify==2.3.0
idna==2.10
iniconfig==1.1.1
isort==5.9.3
jmespath==0.10.0
lark-parser==0.10.1
lazy-object-proxy==1.6.0
mccabe==0.6.1
mypy-boto3-lambda==1.18.60
mypy-boto3-s3==1.18.60
mypy-boto3-sts==1.18.60
nodeenv==1.6.0
packaging==21.0
parver==0.3.1
pep517==0.11.0
pip-tools==6.4.0
platformdirs==2.4.0
pluggy==1.0.0
pre-commit==2.15.0
protobuf==3.19.4
pulumi==3.24.1
pulumi-aws==4.37.2
py==1.10.0
pydantic==1.8.2
pyenchant==3.2.2
pylint==2.11.1
pyparsing==2.4.7
pytest==6.2.5
pytest-mock==3.5.1
pytest-pylint==0.18.0
pytest-randomly==3.6.0
python-dateutil==2.8.2
python-hcl2==3.0.1
python-on-whales==0.27.0
PyYAML==5.4.1
requests==2.26.0
s3transfer==0.5.0
semver==2.13.0
six==1.16.0
stdlib-utils==0.4.7
toml==0.10.2
tomli==1.2.1
tqdm==4.62.3
typer==0.4.0
types-requests==2.25.11
typing-extensions==3.10.0.2
urllib3==1.26.7
virtualenv==20.8.1
wrapt==1.12.1
l
This is not really an automation API specific question, but a question on using assume role for the AWS provider.
Here is a guide that shows doing this for a CLI-driven pulumi program: https://www.pulumi.com/registry/packages/aws/how-to-guides/aws-ts-assume-role/
It shouldn't be much different for automation API, will just need to ensure you set the appropriate environment variables and config values via the automation api methods.
c
Thanks for the tips. I had found that docs page previously, but didn't seem to help. I was able to hack a non-pulumi workaround by just using boto3 to export the role creds to environmental variables when running in CI. In case anyone else runs into the same issue
Copy code
session = boto3.Session()
        assumed_role_object = session.client("sts").assume_role(
            RoleArn=role_arn,
            RoleSessionName=f"deploy--{fully_qualified_stack_name.replace('/','--')}",
        )
        credentials = assumed_role_object["Credentials"]
        os.environ["AWS_ACCESS_KEY_ID"] = credentials["AccessKeyId"]
        os.environ["AWS_SECRET_ACCESS_KEY"] = credentials["SecretAccessKey"]
        os.environ["AWS_SESSION_TOKEN"] = credentials["SessionToken"]
        os.environ["AWS_DEFAULT_REGION"] = "us-east-1"