A Credential in AWX contains authentication information required to connect to remote systems, cloud providers, or external services. Credentials securely store passwords, SSH keys, API tokens, and other sensitive data, making them available to jobs without exposing them to users.
Credentials are AWX’s secure vault for authentication data - they enable automation to access systems while maintaining security best practices.
# From credential.py:278-290def save(self, *args, **kwargs): self.PASSWORD_FIELDS = self.credential_type.secret_fields if self.pk: cred_before = Credential.objects.get(pk=self.pk) inputs_before = cred_before.inputs # Look up the currently persisted value so that we can replace # $encrypted$ with the actual DB-backed value for field in self.PASSWORD_FIELDS: if self.inputs.get(field) == '$encrypted$': self.inputs[field] = inputs_before[field]
Users see $encrypted$ instead of actual values when viewing credentials.
Credentials provide a secure interface for accessing values:
# From credential.py:337-368def get_input(self, field_name, **kwargs): """ Get an injectable and decrypted value for an input field. """ if field_name in self.credential_type.secret_fields: try: return decrypt_field(self, field_name) except AttributeError: for field in self.credential_type.inputs.get('fields', []): if field['id'] == field_name and 'default' in field: return field['default'] if 'default' in kwargs: return kwargs['default'] raise AttributeError(field_name)
At runtime, AWX fetches the password from CyberArk:
# From credential.py:648-679def get_input_value(self, context: dict | None = None): """ Retrieve the value from the external credential backend. """ if context is None: context = {} backend = self.source_credential.credential_type.plugin.backend backend_kwargs = {} for field_name, value in self.source_credential.inputs.items(): if field_name in self.source_credential.credential_type.secret_fields: backend_kwargs[field_name] = decrypt_field(self.source_credential, field_name) else: backend_kwargs[field_name] = value backend_kwargs.update(self.metadata) with set_environ(**settings.AWX_TASK_ENV): return backend(**backend_kwargs)
# From credential.py:312-328def unique_hash(self, display=False): """ Credential exclusivity is not defined solely by the related credential type (due to vault), so this produces a hash that can be used to evaluate exclusivity """ if display: type_alias = self.credential_type.name else: type_alias = self.credential_type_id if self.credential_type.kind == 'vault' and self.has_input('vault_id'): if display: fmt_str = '{} (id={})' else: fmt_str = '{}_{}' return fmt_str.format(type_alias, self.get_input('vault_id')) return str(type_alias)
Multiple vault credentials with different IDs can be used together.
# From credential.py:397-411def validate_role_assignment(self, actor, role_definition, **kwargs): if self.organization: if isinstance(actor, User): if actor.is_superuser: return if Organization.access_qs(actor, 'member').filter(id=self.organization.id).exists(): return requesting_user = kwargs.get('requesting_user', None) if check_resource_server_for_user_in_organization(actor, self.organization, requesting_user): return if isinstance(actor, Team): if actor.organization == self.organization: return raise DRFValidationError({'detail': _(f"You cannot grant credential access to a {actor._meta.object_name} not in the credentials' organization")})