Source code for airflow.providers.amazon.aws.auth_manager.cli.idc_commands
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""User sub-commands."""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
import boto3
from botocore.exceptions import ClientError
from airflow.configuration import conf
from airflow.exceptions import AirflowOptionalProviderFeatureException
from airflow.providers.amazon.aws.auth_manager.constants import CONF_REGION_NAME_KEY, CONF_SECTION_NAME
from airflow.utils import cli as cli_utils
try:
from airflow.utils.providers_configuration_loader import providers_configuration_loaded
except ImportError:
raise AirflowOptionalProviderFeatureException(
"Failed to import avp_commands. This feature is only available in Airflow "
"version >= 2.8.0 where Auth Managers are introduced."
)
if TYPE_CHECKING:
from botocore.client import BaseClient
[docs]log = logging.getLogger(__name__)
@cli_utils.action_cli
@providers_configuration_loaded
[docs]def init_idc(args):
"""Initialize AWS IAM Identity Center resources."""
client = _get_client()
# Create the instance if needed
instance_arn = _create_instance(client, args)
# Create the application if needed
_create_application(client, instance_arn, args)
if not args.dry_run:
print("AWS IAM Identity Center resources created successfully.")
def _get_client():
"""Return AWS IAM Identity Center client."""
region_name = conf.get(CONF_SECTION_NAME, CONF_REGION_NAME_KEY)
return boto3.client("sso-admin", region_name=region_name)
def _create_instance(client: BaseClient, args) -> str | None:
"""Create if needed AWS IAM Identity Center instance."""
instances = client.list_instances()
if args.verbose:
log.debug("Instances found: %s", instances)
if len(instances["Instances"]) > 0:
print(
f"There is already an instance configured in AWS IAM Identity Center: '{instances['Instances'][0]['InstanceArn']}'. "
"No need to create a new one."
)
return instances["Instances"][0]["InstanceArn"]
else:
print("No instance configured in AWS IAM Identity Center, creating one.")
if args.dry_run:
print("Dry run, not creating the instance.")
return None
response = client.create_instance(Name=args.instance_name)
if args.verbose:
log.debug("Response from create_instance: %s", response)
print(f"Instance created: '{response['InstanceArn']}'")
return response["InstanceArn"]
def _create_application(client: BaseClient, instance_arn: str | None, args) -> str | None:
"""Create if needed AWS IAM identity Center application."""
paginator = client.get_paginator("list_applications")
pages = paginator.paginate(InstanceArn=instance_arn or "")
applications = [application for page in pages for application in page["Applications"]]
existing_applications = [
application for application in applications if application["Name"] == args.application_name
]
if args.verbose:
log.debug("Applications found: %s", applications)
log.debug("Existing applications found: %s", existing_applications)
if len(existing_applications) > 0:
print(
f"There is already an application named '{args.application_name}' in AWS IAM Identity Center: '{existing_applications[0]['ApplicationArn']}'. "
"Using this application."
)
return existing_applications[0]["ApplicationArn"]
else:
print(f"No application named {args.application_name} found, creating one.")
if args.dry_run:
print("Dry run, not creating the application.")
return None
try:
response = client.create_application(
ApplicationProviderArn="arn:aws:sso::aws:applicationProvider/custom-saml",
Description="Application automatically created through the Airflow CLI. This application is used to access Airflow environment.",
InstanceArn=instance_arn,
Name=args.application_name,
PortalOptions={
"SignInOptions": {
"Origin": "IDENTITY_CENTER",
},
"Visibility": "ENABLED",
},
Status="ENABLED",
)
if args.verbose:
log.debug("Response from create_application: %s", response)
except ClientError as e:
# This is needed because as of today, the create_application in AWS Identity Center does not support SAML application
# Remove this part when it is supported
if "is not supported for this action" in e.response["Error"]["Message"]:
print(
"Creation of SAML applications is only supported in AWS console today. "
"Please create the application through the console."
)
raise
print(f"Application created: '{response['ApplicationArn']}'")
return response["ApplicationArn"]