imbi-plugin-openai 2.44.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Imbi OpenAI plugin: workload identity federation."""
|
|
2
|
+
|
|
3
|
+
from imbi.plugins.openai.plugin import OpenAIPlugin
|
|
4
|
+
from imbi.plugins.openai.wif import OpenAIExchanger, OpenAIWif
|
|
5
|
+
|
|
6
|
+
PLUGIN = OpenAIPlugin
|
|
7
|
+
|
|
8
|
+
__all__ = ['PLUGIN', 'OpenAIExchanger', 'OpenAIPlugin', 'OpenAIWif']
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""The OpenAI plugin manifest.
|
|
2
|
+
|
|
3
|
+
The plugin has no Integration capability. It adds the ``openai_wif``
|
|
4
|
+
secret provider and the OpenAI token exchanger (for AI Providers).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import imbi.common.plugins as plugins
|
|
8
|
+
from imbi.plugins.openai import wif
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class OpenAIPlugin(plugins.Plugin):
|
|
12
|
+
manifest = plugins.PluginManifest(
|
|
13
|
+
slug='openai',
|
|
14
|
+
name='OpenAI',
|
|
15
|
+
description='OpenAI workload identity federation for model calls',
|
|
16
|
+
icon='si-openai',
|
|
17
|
+
auth_type='none',
|
|
18
|
+
capabilities=[],
|
|
19
|
+
secret_providers=[wif.OpenAIWif],
|
|
20
|
+
token_exchangers=[wif.OpenAIExchanger],
|
|
21
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""OpenAI workload identity federation (WIF plan 3.3, 4.3, 4.5).
|
|
2
|
+
|
|
3
|
+
- :class:`OpenAIExchanger` exchanges an identity JWT for an OpenAI
|
|
4
|
+
access token at a fixed endpoint (D8), with an RFC 8693 token
|
|
5
|
+
exchange.
|
|
6
|
+
- :class:`OpenAIWif` is the ``openai_wif`` secret provider. A dynamic
|
|
7
|
+
binding holds the exchanger target. Each resolution mints a new token
|
|
8
|
+
for the agent of the task through core (``vendor_token``).
|
|
9
|
+
|
|
10
|
+
The subject token and the access token are never logged.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import typing
|
|
14
|
+
|
|
15
|
+
import pydantic
|
|
16
|
+
|
|
17
|
+
from imbi.common.plugins import identity
|
|
18
|
+
|
|
19
|
+
#: Fixed in code (D8). No tenant setting can change it.
|
|
20
|
+
TOKEN_URL = 'https://auth.openai.com/oauth/token'
|
|
21
|
+
_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:token-exchange'
|
|
22
|
+
_SUBJECT_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:jwt'
|
|
23
|
+
|
|
24
|
+
_Id = typing.Annotated[
|
|
25
|
+
str,
|
|
26
|
+
pydantic.StringConstraints(
|
|
27
|
+
min_length=1, max_length=128, pattern=r'^[A-Za-z0-9_-]+$'
|
|
28
|
+
),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _Target(pydantic.BaseModel):
|
|
33
|
+
"""The OpenAI ids of one workload identity provider and account."""
|
|
34
|
+
|
|
35
|
+
model_config = pydantic.ConfigDict(extra='forbid')
|
|
36
|
+
|
|
37
|
+
identity_provider_id: _Id
|
|
38
|
+
service_account_id: _Id
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class OpenAIExchanger(identity.TokenExchanger):
|
|
42
|
+
vendor = 'openai'
|
|
43
|
+
label = 'OpenAI'
|
|
44
|
+
target_help = (
|
|
45
|
+
f'{identity.target_keys(_Target)}, the ids from the OpenAI dashboard.'
|
|
46
|
+
)
|
|
47
|
+
#: The audience of the OpenAI workload identity provider. The
|
|
48
|
+
#: provider in the OpenAI dashboard must use this value.
|
|
49
|
+
audience = 'https://api.openai.com/v1'
|
|
50
|
+
#: An OpenAI token never outlives its subject token. 3300 seconds
|
|
51
|
+
#: keeps the ``aws_sts`` role session at 3600 seconds, the AWS
|
|
52
|
+
#: limit for role chaining (imbi-api on IRSA or EKS Pod Identity).
|
|
53
|
+
jwt_seconds = 3300
|
|
54
|
+
|
|
55
|
+
def validate_target(
|
|
56
|
+
self, target: dict[str, typing.Any]
|
|
57
|
+
) -> dict[str, typing.Any]:
|
|
58
|
+
return identity.validate_model(_Target, target)
|
|
59
|
+
|
|
60
|
+
async def exchange(
|
|
61
|
+
self, target: dict[str, typing.Any], identity_token: str
|
|
62
|
+
) -> identity.AccessToken:
|
|
63
|
+
return await identity.post_exchange(
|
|
64
|
+
'OpenAI',
|
|
65
|
+
TOKEN_URL,
|
|
66
|
+
{
|
|
67
|
+
'grant_type': _GRANT_TYPE,
|
|
68
|
+
'subject_token': identity_token,
|
|
69
|
+
'subject_token_type': _SUBJECT_TOKEN_TYPE,
|
|
70
|
+
**target,
|
|
71
|
+
},
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
EXCHANGER = OpenAIExchanger()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class OpenAIWif(identity.WifSecretProvider):
|
|
79
|
+
"""``openai_wif``: an OpenAI token for the agent of the task."""
|
|
80
|
+
|
|
81
|
+
type = 'openai_wif'
|
|
82
|
+
label = 'OpenAI workload identity'
|
|
83
|
+
exchanger = EXCHANGER
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: imbi-plugin-openai
|
|
3
|
+
Version: 2.44.0
|
|
4
|
+
Summary: OpenAI workload identity federation for Imbi
|
|
5
|
+
Author-email: "Gavin M. Roy" <gavinr@aweber.com>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Natural Language :: English
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Python: >=3.14
|
|
14
|
+
Requires-Dist: imbi-common==2.44.0
|
|
15
|
+
Requires-Dist: pydantic>=2
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# imbi-plugin-openai
|
|
19
|
+
|
|
20
|
+
OpenAI workload identity federation (WIF) for Imbi. The plugin adds:
|
|
21
|
+
|
|
22
|
+
- The OpenAI token exchanger. An OpenAI AI Provider can then use workload
|
|
23
|
+
identity instead of a stored key (Admin, AI Models).
|
|
24
|
+
- The `openai_wif` secret provider. A dynamic binding then mints a
|
|
25
|
+
short-lived OpenAI token for the agent of the task. The harness does
|
|
26
|
+
not use it yet: the Claude Agent SDK calls only the Anthropic API.
|
|
27
|
+
|
|
28
|
+
## How it works
|
|
29
|
+
|
|
30
|
+
1. The organization selects an identity source (for example `aws_sts`) in
|
|
31
|
+
Admin, Secrets, Identity.
|
|
32
|
+
2. In the OpenAI dashboard, create a workload identity provider for the
|
|
33
|
+
issuer of that identity source. Set its audience to
|
|
34
|
+
`https://api.openai.com/v1`. Imbi always requests this audience.
|
|
35
|
+
See the [OpenAI guide](https://developers.openai.com/api/reference/workload-identity-federation).
|
|
36
|
+
3. Create a service account and a mapping. The mapping matches the role
|
|
37
|
+
ARN (`sub`) and the request tag `imbi_ai_provider` (an AI Provider) or
|
|
38
|
+
`imbi_agent` (an agent). AWS request tags are nested in the JWT, so
|
|
39
|
+
expose them with a CEL transformation, for example
|
|
40
|
+
`assertion["https://sts.amazonaws.com/"]["request_tags"]["imbi_ai_provider"]`.
|
|
41
|
+
4. Give Imbi the ids: on the AI Provider (Admin, AI Models, the key icon)
|
|
42
|
+
or in a dynamic `openai_wif` binding.
|
|
43
|
+
5. At use time, Imbi gets a new identity JWT that lasts 55 minutes, and
|
|
44
|
+
exchanges it at `https://auth.openai.com/oauth/token` (RFC 8693). The
|
|
45
|
+
token never outlives the JWT.
|
|
46
|
+
|
|
47
|
+
## Target
|
|
48
|
+
|
|
49
|
+
| Field | Required | Description |
|
|
50
|
+
| ---------------------- | -------- | ----------------------------------------- |
|
|
51
|
+
| `identity_provider_id` | yes | The OpenAI workload identity provider id. |
|
|
52
|
+
| `service_account_id` | yes | The OpenAI service account id. |
|
|
53
|
+
|
|
54
|
+
The provider takes no configuration.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
imbi/plugins/openai/__init__.py,sha256=AF8RgSyQ-1_wxySgEUHsOyNPFNCzaWwot_-J7DQpAfc,265
|
|
2
|
+
imbi/plugins/openai/plugin.py,sha256=vNGYtnSJ242FaFMtrQ0dNZrHKyFeeOaEjSy7V1dbMIQ,618
|
|
3
|
+
imbi/plugins/openai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
imbi/plugins/openai/wif.py,sha256=Gvf-k3j8WZrZxt_9R3UDZ7Jp7mBIzetjD3lbkjC51-w,2567
|
|
5
|
+
imbi_plugin_openai-2.44.0.dist-info/METADATA,sha256=5ESav64AQ8uoe6CnQWGu0mfSwj3_i0BL5IeRC-eWAEE,2469
|
|
6
|
+
imbi_plugin_openai-2.44.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
7
|
+
imbi_plugin_openai-2.44.0.dist-info/RECORD,,
|