Skip to content

Commit b8939b3

Browse files
committed
improve performance with list, fix docs
1 parent cef288f commit b8939b3

5 files changed

Lines changed: 47 additions & 98 deletions

File tree

docs/guide/installation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ alias keep="./vendor/bin/keep"
2424

2525
## Global Installation (Optional)
2626

27-
If you don't plan to use any framework integration, you can install Keep globally:
27+
If you don't plan to use any framework integration, you can install Keep globally and use it as a standalone CLI tool across all your projects.
2828

2929
```bash
3030
composer global require stechstudio/keep

docs/guide/vaults/aws-secrets-manager.md

Lines changed: 31 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ For developers who need complete access to manage secrets across all environment
7272
{
7373
"Sid": "ListSecretsAccountWide",
7474
"Effect": "Allow",
75-
"Action": "secretsmanager:ListSecrets",
75+
"Action": [
76+
"secretsmanager:ListSecrets",
77+
"secretsmanager:BatchGetSecretValue"
78+
],
7679
"Resource": "*"
7780
},
7881
{
@@ -117,17 +120,17 @@ For developers who should only access development and staging environments:
117120
"Version": "2012-10-17",
118121
"Statement": [
119122
{
120-
"Sid": "ReadWriteDevStagingSecrets",
123+
"Sid": "ReadWriteMyAppStagingAndProd",
121124
"Effect": "Allow",
122125
"Action": [
123126
"secretsmanager:GetSecretValue",
124-
"secretsmanager:BatchGetSecretValue",
125127
"secretsmanager:DescribeSecret",
126128
"secretsmanager:ListSecretVersionIds",
127129
"secretsmanager:PutSecretValue",
128130
"secretsmanager:UpdateSecret",
129131
"secretsmanager:UpdateSecretVersionStage",
130132
"secretsmanager:DeleteSecret",
133+
"secretsmanager:RestoreSecret",
131134
"secretsmanager:TagResource",
132135
"secretsmanager:UntagResource"
133136
],
@@ -138,27 +141,24 @@ For developers who should only access development and staging environments:
138141
"secretsmanager:ResourceTag/Namespace": "myapp"
139142
},
140143
"ForAnyValue:StringEquals": {
141-
"secretsmanager:ResourceTag/Stage": ["development", "staging"]
144+
"secretsmanager:ResourceTag/Stage": [
145+
"staging",
146+
"production"
147+
]
142148
}
143149
}
144150
},
145151
{
146-
"Sid": "ListOnlyMyAppDevStagingSecrets",
152+
"Sid": "ListSecretsAccountWide",
147153
"Effect": "Allow",
148-
"Action": "secretsmanager:ListSecrets",
149-
"Resource": "*",
150-
"Condition": {
151-
"StringEquals": {
152-
"secretsmanager:ResourceTag/ManagedBy": "Keep",
153-
"secretsmanager:ResourceTag/Namespace": "myapp"
154-
},
155-
"ForAnyValue:StringEquals": {
156-
"secretsmanager:ResourceTag/Stage": ["development", "staging"]
157-
}
158-
}
154+
"Action": [
155+
"secretsmanager:ListSecrets",
156+
"secretsmanager:BatchGetSecretValue"
157+
],
158+
"Resource": "*"
159159
},
160160
{
161-
"Sid": "CreateSecretsInDevStaging",
161+
"Sid": "CreateSecretsInStagingAndProd",
162162
"Effect": "Allow",
163163
"Action": "secretsmanager:CreateSecret",
164164
"Resource": "*",
@@ -168,28 +168,18 @@ For developers who should only access development and staging environments:
168168
"aws:RequestTag/Namespace": "myapp"
169169
},
170170
"ForAnyValue:StringEquals": {
171-
"aws:RequestTag/Stage": ["development", "staging"]
171+
"aws:RequestTag/Stage": [
172+
"staging",
173+
"production"
174+
]
172175
},
173176
"ForAllValues:StringEquals": {
174-
"aws:TagKeys": ["ManagedBy", "Namespace", "Stage", "VaultSlug"]
175-
}
176-
}
177-
},
178-
{
179-
"Sid": "DenyProductionAccess",
180-
"Effect": "Deny",
181-
"Action": [
182-
"secretsmanager:GetSecretValue",
183-
"secretsmanager:BatchGetSecretValue",
184-
"secretsmanager:DescribeSecret",
185-
"secretsmanager:PutSecretValue",
186-
"secretsmanager:UpdateSecret",
187-
"secretsmanager:DeleteSecret"
188-
],
189-
"Resource": "*",
190-
"Condition": {
191-
"StringEquals": {
192-
"secretsmanager:ResourceTag/Stage": "production"
177+
"aws:TagKeys": [
178+
"ManagedBy",
179+
"Namespace",
180+
"Stage",
181+
"VaultSlug"
182+
]
193183
}
194184
}
195185
},
@@ -216,45 +206,26 @@ For production deployment processes that only need to read production secrets:
216206
"Version": "2012-10-17",
217207
"Statement": [
218208
{
219-
"Sid": "ReadOnlyProductionSecrets",
209+
"Sid": "ReadOnlyMyAppProduction",
220210
"Effect": "Allow",
221211
"Action": [
222212
"secretsmanager:GetSecretValue",
223-
"secretsmanager:BatchGetSecretValue",
224213
"secretsmanager:DescribeSecret"
225214
],
226215
"Resource": "*",
227216
"Condition": {
228217
"StringEquals": {
229-
"secretsmanager:ResourceTag/ManagedBy": "Keep",
230218
"secretsmanager:ResourceTag/Namespace": "myapp",
231219
"secretsmanager:ResourceTag/Stage": "production"
232220
}
233221
}
234222
},
235223
{
236-
"Sid": "ListOnlyProductionSecrets",
224+
"Sid": "ListSecretsAccountWide",
237225
"Effect": "Allow",
238-
"Action": "secretsmanager:ListSecrets",
239-
"Resource": "*",
240-
"Condition": {
241-
"StringEquals": {
242-
"secretsmanager:ResourceTag/ManagedBy": "Keep",
243-
"secretsmanager:ResourceTag/Namespace": "myapp",
244-
"secretsmanager:ResourceTag/Stage": "production"
245-
}
246-
}
247-
},
248-
{
249-
"Sid": "DenyWriteOperations",
250-
"Effect": "Deny",
251226
"Action": [
252-
"secretsmanager:CreateSecret",
253-
"secretsmanager:PutSecretValue",
254-
"secretsmanager:UpdateSecret",
255-
"secretsmanager:DeleteSecret",
256-
"secretsmanager:TagResource",
257-
"secretsmanager:UntagResource"
227+
"secretsmanager:ListSecrets",
228+
"secretsmanager:BatchGetSecretValue"
258229
],
259230
"Resource": "*"
260231
},

src/Vaults/AwsSecretsManagerVault.php

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public function list(): SecretCollection
8282

8383
do {
8484
$params = [
85-
'MaxResults' => 100, // AWS Secrets Manager max
85+
'MaxResults' => 20,
8686
'Filters' => [
8787
[
8888
'Key' => 'tag-key',
@@ -116,14 +116,10 @@ public function list(): SecretCollection
116116
$params['NextToken'] = $nextToken;
117117
}
118118

119-
$result = $this->client()->listSecrets($params);
119+
$result = $this->client()->batchGetSecretValue($params);
120120

121-
foreach ($result->get('SecretList') as $secret) {
121+
foreach ($result->get('SecretValues') as $secret) {
122122
$secretName = $secret['Name'];
123-
$currentVersion = Arr::first(
124-
array_keys($secret['SecretVersionsToStages']),
125-
fn($key) => in_array('AWSCURRENT', $secret['SecretVersionsToStages'][$key] ?? [], true)
126-
);
127123

128124
// Extract the key from the full secret name using the expected format
129125
$expectedPrefix = Keep::getNamespace().'/'.$this->stage.'/';
@@ -142,29 +138,16 @@ public function list(): SecretCollection
142138
continue;
143139
}
144140

145-
// Get the actual secret value
146-
try {
147-
$secretValue = $this->client()->getSecretValue([
148-
'SecretId' => $secretName,
149-
]);
150-
151-
$value = $secretValue->get('SecretString');
152-
$isSecure = true; // AWS Secrets Manager always encrypts
153-
154-
$secrets->push(Secret::fromVault(
155-
key: $key,
156-
value: $value,
157-
encryptedValue: null,
158-
secure: $isSecure,
159-
stage: $this->stage,
160-
revision: $currentVersion,
161-
path: $secretName,
162-
vault: $this,
163-
));
164-
} catch (SecretsManagerException $e) {
165-
// Skip secrets we can't read (permission issues, etc.)
166-
continue;
167-
}
141+
$secrets->push(Secret::fromVault(
142+
key: $key,
143+
value: $secret['SecretString'] ?? null,
144+
encryptedValue: null,
145+
secure: true,
146+
stage: $this->stage,
147+
revision: $secret['VersionId'] ?? 1,
148+
path: $secretName,
149+
vault: $this,
150+
));
168151
}
169152

170153
$nextToken = $result->get('NextToken');
@@ -336,7 +319,7 @@ public function history(string $key, FilterCollection $filters, ?int $limit = 10
336319
$histories->push(new SecretHistory(
337320
key: $key,
338321
value: $secretValue->get('SecretString'),
339-
version: intval($version['VersionId'] ?? 1),
322+
version: $version['VersionId'] ?? 1,
340323
lastModifiedDate: isset($version['CreatedDate']) ? Carbon::parse($version['CreatedDate']) : null,
341324
lastModifiedUser: null, // AWS Secrets Manager doesn't track user info
342325
dataType: 'SecretString',

src/Vaults/AwsSsmVault.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ public static function configure(array $existingSettings = []): array
5151

5252
public function format(?string $key = null): string
5353
{
54-
if (is_callable($this->keyFormatter)) {
55-
return call_user_func($this->keyFormatter, $key, $this->stage, $this->config);
56-
}
57-
5854
return Str::of($this->config['prefix'] ?? '')
5955
->start('/')->finish('/')
6056
->append(Keep::getNamespace().'/')

tests/Support/TestVault.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,7 @@ public function format(?string $key = null): string
108108
return sprintf('/%s/%s/', $this->config['namespace'] ?? 'test-app', $this->stage);
109109
}
110110

111-
$formatter = $this->keyFormatter ?? fn ($k) => strtoupper($k);
112-
$formattedKey = call_user_func($formatter, $key);
111+
$formattedKey = strtoupper($key);
113112

114113
return sprintf('/%s/%s/%s', $this->config['namespace'] ?? 'test-app', $this->stage, $formattedKey);
115114
}

0 commit comments

Comments
 (0)